commit a36348ead1935e5946b063666d1bcadcd1c43545 Author: Sylvain Zimmer Date: Fri Jan 9 00:51:25 2026 +0100 🎉(all) bootstrap the Calendars project This repository was forked from Drive in late December 2025 and boostraped as a minimal demo of backend+caldav server+frontend integration. There is much left to do and to fix! diff --git a/.cursor/rules/django-python.mdc b/.cursor/rules/django-python.mdc new file mode 100644 index 0000000..0270cbc --- /dev/null +++ b/.cursor/rules/django-python.mdc @@ -0,0 +1,77 @@ +--- +description: Rules for writing Python with Django +globs: src/backend/**/*.py +alwaysApply: false +--- +You are an expert in Python, Django, and scalable web application development. + +Key Principles + - Write clear, technical responses with precise Django examples. + - Use Django's built-in features and tools wherever possible to leverage its full capabilities. + - Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance for the most part, with the one exception being 100 characters per line instead of 79). + - Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables). + +Django/Python + - Use Django REST Framework viewsets for API endpoints. + - Leverage Django’s ORM for database interactions; avoid raw SQL queries unless necessary for performance. + - Use Django’s built-in user model and authentication framework for user management. + - Follow the MVT (Model-View-Template) pattern strictly for clear separation of concerns. + - Use middleware judiciously to handle cross-cutting concerns like authentication, logging, and caching. + +Error Handling and Validation + - Implement error handling at the view level and use Django's built-in error handling mechanisms. + - Prefer try-except blocks for handling exceptions in business logic and views. + +Dependencies + - Django + - Django REST Framework (for API development) + - Celery (for background tasks) + - Redis (for caching and task queues) + - PostgreSQL (preferred databases for production) + - Minio (file storage for production) + - OIDC prodiver (for managing authentication) + +Django-Specific Guidelines + - Use Django templates for rendering HTML and DRF serializers for JSON responses. + - Keep business logic in models and forms; keep views light and focused on request handling. + - Use Django's URL dispatcher (urls.py) to define clear and RESTful URL patterns. + - Apply Django's security best practices (e.g., CSRF protection, SQL injection protection, XSS prevention). + - Use Django’s built-in tools for testing (pytest-django) to ensure code quality and reliability. + - Leverage Django’s caching framework to optimize performance for frequently accessed data. + - Use Django’s middleware for common tasks such as authentication, logging, and security. + +Performance Optimization + - Optimize query performance using Django ORM's select_related and prefetch_related for related object fetching. + - Use Django’s cache framework with backend support (e.g., Redis or Memcached) to reduce database load. + - Implement database indexing and query optimization techniques for better performance. + - Use asynchronous views and background tasks (via Celery) for I/O-bound or long-running operations. + - Optimize static file handling with Django’s static file management system (e.g., WhiteNoise). + +Logging + - As a general rule, we should have logs for every expected and unexpected actions of the application, using the appropriate log level. + - We should also be logging these exceptions to Sentry with the Sentry Python SDK. Python exceptions should almost always be captured automatically without extra instrumentation, but custom ones (such as failed requests to external services, query errors, or Celery task failures) can be tracked using capture_exception(). + +Log Levels + - A log level or log severity is a piece of information telling how important a given log message is: + - DEBUG: should be used for information that may be needed for diagnosing issues and troubleshooting or when running application in the test environment for the purpose of making sure everything is running correctly + - INFO: should be used as standard log level, indicating that something happened + - WARN: should be used when something unexpected happened but the code can continue the work + - ERROR: should be used when the application hits an issue preventing one or more functionalities from properly functioning + +Security + - Don’t log sensitive information. Make sure you never log: + - authorization tokens + - passwords + - financial data + - health data + - PII (Personal Identifiable Information) + +Testing + - All new packages and most new significant functionality should come with unit tests + +Unit tests + - A good unit test should: + - focus on a single use-case at a time + - have a minimal set of assertions per test + - demonstrate every use case. The rule of thumb is: if it can happen, it should be covered +Refer to Django documentation for best practices in views, models, forms, and security considerations. diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..24e79d0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,6 @@ + diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md new file mode 100644 index 0000000..53aba2e --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -0,0 +1,28 @@ +--- +name: 🐛 Bug Report +about: If something is not working as expected 🤔. + +--- + +## Bug Report + +**Problematic behavior** +A clear and concise description of the behavior. + +**Expected behavior/code** +A clear and concise description of what you expected to happen (or code). + +**Steps to Reproduce** +1. Do this... +2. Then this... +3. And then the bug happens! + +**Environment** +- Calendars version: +- Platform: + +**Possible Solution** + + +**Additional context/Screenshots** +Add any other context about the problem here. If applicable, add screenshots to help explain. diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md new file mode 100644 index 0000000..51d3170 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -0,0 +1,23 @@ +--- +name: ✨ Feature Request +about: I have a suggestion (and may want to build it 💪)! + +--- + +## Feature Request + +**Is your feature request related to a problem or unsupported use case? Please describe.** +A clear and concise description of what the problem is. For example: I need to do some task and I have an issue... + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. Add any considered drawbacks. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Discovery, Documentation, Adoption, Migration Strategy** +If you can, explain how users will be able to use this and possibly write out a version the docs (if applicable). +Maybe a screenshot or design? + +**Do you want to work on it through a Pull Request?** + diff --git a/.github/ISSUE_TEMPLATE/Support_question.md b/.github/ISSUE_TEMPLATE/Support_question.md new file mode 100644 index 0000000..d73b0fc --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Support_question.md @@ -0,0 +1,22 @@ +--- +name: 🤗 Support Question +about: If you have a question 💬, or something was not clear from the docs! + +--- + + + +--- + +Please make sure you have read our [main Readme](https://github.com/suitenumerique/calendars). + +Also make sure it was not already answered in [an open or close issue](https://github.com/suitenumerique/calendars/issues). + +If your question was not covered, and you feel like it should be, fire away! We'd love to improve our docs! 👌 + +**Topic** +What's the general area of your question: for example, docker setup, database schema, search functionality,... + +**Question** +Try to be as specific as possible so we can help you as best we can. Please be patient 🙏 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..85cfbe6 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,11 @@ +## Purpose + +Description... + + +## Proposal + +Description... + +- [] item 1... +- [] item 2... diff --git a/.github/workflows/calendars-frontend.yml b/.github/workflows/calendars-frontend.yml new file mode 100644 index 0000000..317473e --- /dev/null +++ b/.github/workflows/calendars-frontend.yml @@ -0,0 +1,114 @@ +name: Frontend Workflow + +on: + push: + branches: + - main + pull_request: + branches: + - "*" + +jobs: + install-front: + uses: ./.github/workflows/front-dependencies-installation.yml + with: + node_version: "22.x" + + lint-front: + runs-on: ubuntu-latest + needs: install-front + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22.x" + - name: Restore the frontend cache + uses: actions/cache@v4 + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} + fail-on-cache-miss: true + + - name: Check linting + run: cd src/frontend/ && yarn lint + + test-unit: + runs-on: ubuntu-latest + needs: install-front + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22.x" + + - name: Restore the frontend cache + uses: actions/cache@v4 + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} + fail-on-cache-miss: true + + - name: Run unit tests + run: | + cd src/frontend/apps/calendars + yarn test + + test-e2e: + runs-on: ubuntu-latest + needs: install-front + strategy: + matrix: + browser: + - chromium + - webkit + - firefox + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "22.x" + + - name: Restore the frontend cache + uses: actions/cache@v4 + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} + fail-on-cache-miss: true + + - name: Install Playwright Browsers + run: | + cd src/frontend/apps/e2e + npx playwright install --with-deps ${{matrix.browser}} + + - name: Start Docker services + run: | + make bootstrap-e2e + + - name: Start frontend + run: | + cd src/frontend && yarn dev & + + - name: Wait for Keycloak to be ready + run: | + timeout 30 bash -c 'while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' http://localhost:8083/)" != "302" ]]; do echo "Waiting for Keycloak..." && sleep 2; done' && echo "Keycloak is ready!" + + - name: Run e2e tests + run: | + cd src/frontend/apps/e2e + yarn test --project=${{ matrix.browser }} + + - uses: actions/upload-artifact@v4 + if: always() + with: + name: report-${{ matrix.browser }} + path: src/frontend/apps/e2e/report/ + retention-days: 7 diff --git a/.github/workflows/calendars.yml b/.github/workflows/calendars.yml new file mode 100644 index 0000000..9de8b6e --- /dev/null +++ b/.github/workflows/calendars.yml @@ -0,0 +1,187 @@ +name: Main Workflow + +on: + push: + branches: + - main + pull_request: + branches: + - "*" + +jobs: + lint-git: + runs-on: ubuntu-latest + if: github.event_name == 'pull_request' # Makes sense only for pull requests + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: show + run: git log + - name: Enforce absence of print statements in code + if: always() + run: | + ! git diff origin/${{ github.event.pull_request.base.ref }}..HEAD -- . ':(exclude)**/calendars.yml' | grep "print(" + - name: Check absence of fixup commits + if: always() + run: | + ! git log | grep 'fixup!' + - name: Install gitlint + if: always() + run: pip install --user requests gitlint + - name: Lint commit messages added to main + if: always() + run: ~/.local/bin/gitlint --commits origin/${{ github.event.pull_request.base.ref }}..HEAD + + check-changelog: + runs-on: ubuntu-latest + if: | + contains(github.event.pull_request.labels.*.name, 'noChangeLog') == false && + github.event_name == 'pull_request' + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 50 + - name: Check that the CHANGELOG has been modified in the current branch + run: git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.event.after }} | grep 'CHANGELOG.md' + + lint-changelog: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + - name: Check CHANGELOG max line length + run: | + max_line_length=$(cat CHANGELOG.md | grep -Ev "^\[.*\]: https://github.com" | wc -L) + if [ $max_line_length -ge 80 ]; then + echo "ERROR: CHANGELOG has lines longer than 80 characters." + exit 1 + fi + + lint-back: + runs-on: ubuntu-latest + defaults: + run: + working-directory: src/backend + steps: + - name: Checkout repository + uses: actions/checkout@v6 + - name: "Set up Python" + uses: actions/setup-python@v6 + with: + python-version-file: "src/backend/pyproject.toml" + - name: Install uv + uses: astral-sh/setup-uv@v6 + - name: Install the project + run: uv sync --locked --all-extras + + - name: Check code formatting with ruff + run: uv run ruff format . --diff + - name: Lint code with ruff + run: uv run ruff check . + - name: Lint code with pylint + run: uv run pylint . + + test-back: + runs-on: ubuntu-latest + needs: build-mails + + defaults: + run: + working-directory: src/backend + + services: + postgres: + image: postgres:16 + env: + POSTGRES_DB: calendars + POSTGRES_USER: pgroot + POSTGRES_PASSWORD: pass + ports: + - 5432:5432 + # needed because the postgres container does not provide a healthcheck + options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 + + env: + DJANGO_CONFIGURATION: Test + DJANGO_SETTINGS_MODULE: calendars.settings + DJANGO_SECRET_KEY: ThisIsAnExampleKeyForTestPurposeOnly + OIDC_OP_JWKS_ENDPOINT: /endpoint-for-test-purpose-only + DJANGO_EMAIL_HOST: mailcatcher + DB_HOST: localhost + DB_NAME: calendars + DB_USER: pgroot + DB_PASSWORD: pass + DB_PORT: 5432 + STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage + AWS_S3_ENDPOINT_URL: http://localhost:9000 + AWS_S3_ACCESS_KEY_ID: calendar + AWS_S3_SECRET_ACCESS_KEY: password + MEDIA_BASE_URL: http://localhost:8083 + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Create writable /data + run: | + sudo mkdir -p /data/media && \ + sudo mkdir -p /data/static + + - name: Restore the mail templates + uses: actions/cache@v4 + id: mail-templates + with: + path: "src/backend/core/templates/mail" + key: mail-templates-${{ hashFiles('src/mail/mjml') }} + + - name: Start MinIO + run: | + docker pull minio/minio + docker run -d --name minio \ + -p 9000:9000 \ + -e "MINIO_ACCESS_KEY=calendar" \ + -e "MINIO_SECRET_KEY=password" \ + -v /data/media:/data \ + minio/minio server --console-address :9001 /data + + # Tool to wait for a service to be ready + - name: Install Dockerize + run: | + curl -sSL https://github.com/jwilder/dockerize/releases/download/v0.8.0/dockerize-linux-amd64-v0.8.0.tar.gz | sudo tar -C /usr/local/bin -xzv + + - name: Wait for MinIO to be ready + run: | + dockerize -wait tcp://localhost:9000 -timeout 10s + + - name: Configure MinIO + run: | + MINIO=$(docker ps | grep minio/minio | sed -E 's/.*\s+([a-zA-Z0-9_-]+)$/\1/') + docker exec ${MINIO} sh -c \ + "mc alias set calendar http://localhost:9000 calendar password && \ + mc alias ls && \ + mc mb calendar/calendar-media-storage && \ + mc version enable calendar/calendar-media-storage" + + - name: "Set up Python" + uses: actions/setup-python@v6 + with: + python-version-file: "src/backend/pyproject.toml" + - name: Install uv + uses: astral-sh/setup-uv@v6 + - name: Install the dependencies + run: uv sync --locked --all-extras + + - name: Install gettext (required to compile messages) and MIME support + run: | + sudo apt-get update + sudo apt-get install -y gettext pandoc shared-mime-info + sudo wget https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types -O /etc/mime.types + + - name: Generate a MO file from strings extracted from the project + run: uv run python manage.py compilemessages + + - name: Run tests + run: uv run pytest -n 2 diff --git a/.github/workflows/crowdin_download.yml b/.github/workflows/crowdin_download.yml new file mode 100644 index 0000000..aa9d657 --- /dev/null +++ b/.github/workflows/crowdin_download.yml @@ -0,0 +1,76 @@ +name: Download translations from Crowdin + +on: + workflow_dispatch: + push: + branches: + - 'release/**' + +jobs: + install-front: + uses: ./.github/workflows/front-dependencies-installation.yml + with: + node_version: '20.x' + + synchronize-with-crowdin: + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Create empty source files + run: | + touch src/backend/locale/django.pot + mkdir -p src/frontend/packages/i18n/locales/impress/ + touch src/frontend/packages/i18n/locales/impress/translations-crowdin.json + # crowdin workflow + - name: crowdin action + uses: crowdin/github-action@v2 + with: + config: crowdin/config.yml + upload_sources: false + upload_translations: false + download_translations: true + create_pull_request: false + push_translations: false + push_sources: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # A numeric ID, found at https://crowdin.com/project//tools/api + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + + # Visit https://crowdin.com/settings#api-key to create this token + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + + CROWDIN_BASE_PATH: "../src/" + # frontend i18n + - name: Restore the frontend cache + uses: actions/cache@v4 + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} + fail-on-cache-miss: true + - name: generate translations files + working-directory: src/frontend + run: yarn i18n:deploy + # Create a new PR + - name: Create a new Pull Request with new translated strings + uses: peter-evans/create-pull-request@v7 + with: + commit-message: | + 🌐(i18n) update translated strings + + Update translated files with new translations + title: 🌐(i18n) update translated strings + body: | + ## Purpose + + update translated strings + + ## Proposal + + - [x] update translated strings + branch: i18n/update-translations + labels: i18n diff --git a/.github/workflows/crowdin_upload.yml b/.github/workflows/crowdin_upload.yml new file mode 100644 index 0000000..000ecca --- /dev/null +++ b/.github/workflows/crowdin_upload.yml @@ -0,0 +1,68 @@ +name: Update crowdin sources + +on: + workflow_dispatch: + push: + branches: + - main + +jobs: + install-front: + uses: ./.github/workflows/front-dependencies-installation.yml + with: + node_version: '20.x' + + synchronize-with-crowdin: + needs: install-front + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v6 + # Backend i18n + - name: Install Python + uses: actions/setup-python@v6 + with: + python-version: "3.13.9" + cache: 'pip' + - name: Upgrade pip and setuptools + run: pip install --upgrade pip setuptools + - name: Install development dependencies + run: pip install --user . + working-directory: src/backend + - name: Install gettext + run: | + sudo apt-get update + sudo apt-get install -y gettext pandoc + - name: generate pot files + working-directory: src/backend + run: | + DJANGO_CONFIGURATION=Build python manage.py makemessages -a --keep-pot + # frontend i18n + - name: Restore the frontend cache + uses: actions/cache@v4 + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} + fail-on-cache-miss: true + - name: generate source translation file + working-directory: src/frontend + run: yarn i18n:extract + # crowdin workflow + - name: crowdin action + uses: crowdin/github-action@v2 + with: + config: crowdin/config.yml + upload_sources: true + upload_translations: false + download_translations: false + create_pull_request: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + # A numeric ID, found at https://crowdin.com/project//tools/api + CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }} + + # Visit https://crowdin.com/settings#api-key to create this token + CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }} + + CROWDIN_BASE_PATH: "../src/" diff --git a/.github/workflows/docker-hub.yml b/.github/workflows/docker-hub.yml new file mode 100644 index 0000000..dc55946 --- /dev/null +++ b/.github/workflows/docker-hub.yml @@ -0,0 +1,104 @@ +name: Docker Hub Workflow +run-name: Docker Hub Workflow + +on: + workflow_dispatch: + push: + branches: + - 'main' + tags: + - 'v*' + pull_request: + branches: + - 'main' + +env: + DOCKER_USER: 1001:127 + +jobs: + build-and-push-backend: + runs-on: ubuntu-latest + steps: + - + name: Checkout repository + uses: actions/checkout@v6 + - + name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: lasuite/calendars-backend + - + name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + - + name: Run trivy scan + uses: numerique-gouv/action-trivy-cache@main + with: + docker-build-args: '--target backend-production -f Dockerfile' + docker-image-name: 'docker.io/lasuite/calendars-backend:${{ github.sha }}' + - + name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + target: backend-production + build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + build-and-push-frontend: + runs-on: ubuntu-latest + steps: + - + name: Checkout repository + uses: actions/checkout@v6 + - + name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: lasuite/calendars-frontend + - + name: Login to DockerHub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_PASSWORD }} + - + name: Run trivy scan + uses: numerique-gouv/action-trivy-cache@main + with: + docker-build-args: '-f src/frontend/Dockerfile --target frontend-production' + docker-image-name: 'docker.io/lasuite/calendars-frontend:${{ github.sha }}' + - + name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + file: ./src/frontend/Dockerfile + target: frontend-production + build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000 + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + notify-argocd: + needs: + - build-and-push-frontend + - build-and-push-backend + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + steps: + - uses: numerique-gouv/action-argocd-webhook-notification@main + id: notify + with: + deployment_repo_path: "${{ secrets.DEPLOYMENT_REPO_URL }}" + argocd_webhook_secret: "${{ secrets.ARGOCD_PREPROD_WEBHOOK_SECRET }}" + argocd_url: "${{ vars.ARGOCD_PREPROD_WEBHOOK_URL }}" diff --git a/.github/workflows/front-dependencies-installation.yml b/.github/workflows/front-dependencies-installation.yml new file mode 100644 index 0000000..f95153d --- /dev/null +++ b/.github/workflows/front-dependencies-installation.yml @@ -0,0 +1,36 @@ +name: Install frontend installation reusable workflow + +on: + workflow_call: + inputs: + node_version: + required: false + default: '20.x' + type: string + +jobs: + front-dependencies-installation: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v6 + - name: Restore the frontend cache + uses: actions/cache@v4 + id: front-node_modules + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} + - name: Setup Node.js + if: steps.front-node_modules.outputs.cache-hit != 'true' + uses: actions/setup-node@v4 + with: + node-version: ${{ inputs.node_version }} + - name: Install dependencies + if: steps.front-node_modules.outputs.cache-hit != 'true' + run: cd src/frontend/ && yarn install --frozen-lockfile + - name: Cache install frontend + if: steps.front-node_modules.outputs.cache-hit != 'true' + uses: actions/cache@v4 + with: + path: "src/frontend/**/node_modules" + key: front-node_modules-${{ hashFiles('src/frontend/**/yarn.lock') }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..083bf55 --- /dev/null +++ b/.gitignore @@ -0,0 +1,84 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +.DS_Store +.next/ + +# Translations # Translations +*.mo +*.pot + +# Environments +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ +env.d/development/*.local +env.d/terraform + +# Docker +compose.override.yml +docker/auth/*.local + +# npm +node_modules + +# Mails +src/backend/core/templates/mail/ + +# Swagger +**/swagger.json + +# Logs +*.log + +# Terraform +.terraform +*.tfstate +*.tfstate.backup + +# Test & lint +.coverage +.pylint.d +.pytest_cache +db.sqlite3 +.mypy_cache + +# Site media +/data/ + +# IDEs +.idea/ +.vscode/ +*.iml +.devcontainer + +# Various +.turbo diff --git a/.gitlint b/.gitlint new file mode 100644 index 0000000..f7373b6 --- /dev/null +++ b/.gitlint @@ -0,0 +1,78 @@ +# All these sections are optional, edit this file as you like. +[general] +# Ignore certain rules, you can reference them by their id or by their full name +# ignore=title-trailing-punctuation, T3 + +# verbosity should be a value between 1 and 3, the commandline -v flags take precedence over this +# verbosity = 2 + +# By default gitlint will ignore merge commits. Set to 'false' to disable. +# ignore-merge-commits=true + +# By default gitlint will ignore fixup commits. Set to 'false' to disable. +# ignore-fixup-commits=true + +# By default gitlint will ignore squash commits. Set to 'false' to disable. +# ignore-squash-commits=true + +# Enable debug mode (prints more output). Disabled by default. +# debug=true + +# Set the extra-path where gitlint will search for user defined rules +# See http://jorisroovers.github.io/gitlint/user_defined_rules for details +extra-path=gitlint/ + +# [title-max-length] +# line-length=80 + +[title-must-not-contain-word] +# Comma-separated list of words that should not occur in the title. Matching is case +# insensitive. It's fine if the keyword occurs as part of a larger word (so "WIPING" +# will not cause a violation, but "WIP: my title" will. +words=wip + +#[title-match-regex] +# python like regex (https://docs.python.org/2/library/re.html) that the +# commit-msg title must be matched to. +# Note that the regex can contradict with other rules if not used correctly +# (e.g. title-must-not-contain-word). +#regex= + +# [B1] +# B1 = body-max-line-length +# line-length=120 +# [body-min-length] +# min-length=5 + +# [body-is-missing] +# Whether to ignore this rule on merge commits (which typically only have a title) +# default = True +# ignore-merge-commits=false + +# [body-changed-file-mention] +# List of files that need to be explicitly mentioned in the body when they are changed +# This is useful for when developers often erroneously edit certain files or git submodules. +# By specifying this rule, developers can only change the file when they explicitly reference +# it in the commit message. +# files=gitlint/rules.py,README.md + +# [author-valid-email] +# python like regex (https://docs.python.org/2/library/re.html) that the +# commit author email address should be matched to +# For example, use the following regex if you only want to allow email addresses from foo.com +# regex=[^@]+@foo.com + +[ignore-by-title] +# Allow empty body & wrong title pattern only when bots (pyup/greenkeeper) +# upgrade dependencies +regex=^(⬆️.*|Update (.*) from (.*) to (.*)|(chore|fix)\(package\): update .*)$ +ignore=B6,UC1 + +# [ignore-by-body] +# Ignore certain rules for commits of which the body has a line that matches a regex +# E.g. Match bodies that have a line that that contain "release" +# regex=(.*)release(.*) +# +# Ignore certain rules, you can reference them by their id or by their full name +# Use 'all' to ignore all rules +# ignore=T1,body-min-length diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..56414d7 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,79 @@ +# Contributor Covenant Code of Conduct +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +- Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. +- Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +- This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +- Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at contact@suite.anct.gouv.fr. + +- All complaints will be reviewed and investigated promptly and fairly. + +- All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +- Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of the following Code of Conduct + +## Code of Conduct: + +### 1. Correction + +Community Impact: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +Consequence: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +Community Impact: A violation through a single incident or series of actions. + +Consequence: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +Community Impact: A serious violation of community standards, including sustained inappropriate behavior. + +Consequence: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +Community Impact: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +Consequence: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the Contributor Covenant, version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html. + +Community Impact Guidelines were inspired by Mozilla's [code of conduct enforcement ladder](https://github.com/mozilla/inclusion/blob/master/code-of-conduct-enforcement/consequence-ladder.md). + +For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..d1ed138 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,84 @@ +# Contributing to the Project + +Thank you for taking the time to contribute! Please follow these guidelines to ensure a smooth and productive workflow. 🚀🚀🚀 + +To get started with the project, please refer to the [README.md](https://github.com/suitenumerique/calendars/blob/main/README.md) for detailed instructions on how to run Calendars locally. + +Contributors are required to sign off their commits with `git commit --signoff`: this confirms that they have read and accepted the [Developer's Certificate of Origin 1.1](https://developercertificate.org/). For security reasons please [sign your commits with your SSH or GPG key](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification) with `git commit -S`. + +Please also check out our [dev handbook](https://suitenumerique.gitbook.io/handbook) to learn our best practices. + +## Creating an Issue + +When creating an issue, please provide the following details: + +1. **Title**: A concise and descriptive title for the issue. +2. **Description**: A detailed explanation of the issue, including relevant context or screenshots if applicable. +3. **Steps to Reproduce**: If the issue is a bug, include the steps needed to reproduce the problem. +4. **Expected vs. Actual Behavior**: Describe what you expected to happen and what actually happened. +5. **Labels**: Add appropriate labels to categorize the issue (e.g., bug, feature request, documentation). + +## Commit Message Format + +All commit messages must adhere to the following format: + +`(type) title description` + +* <**gitmoji**>: Use a gitmoji to represent the purpose of the commit. For example, ✨ for adding a new feature or 🔥 for removing something, see the list [here](https://gitmoji.dev/). +* **(type)**: Describe the type of change. Common types include `backend`, `frontend`, `CI`, `docker` etc... +* **title**: A short, descriptive title for the change (*) +* **blank line after the commit title +* **description**: Include additional details on why you made the changes (**). + +(*) ⚠️ **Make sure you add no space between the emoji and the (type) but add a space after the closing parenthesis of the type and use no caps!** + +(**) ⚠️ **Commit description message is mandatory and shouldn't be too long** + +### Example Commit Message + +``` +✨(frontend) add user authentication logic + +Implemented login and signup features, and integrated OAuth2 for social login. +``` + +## Changelog Update + +Please add a line to the changelog describing your development. The changelog entry should include a brief summary of the changes, this helps in tracking changes effectively and keeping everyone informed. We usually include the title of the pull request, followed by the pull request ID to finish the log entry. The changelog line should be less than 80 characters in total. + +### Example Changelog Message +``` +## [Unreleased] + +## Added + +- ✨(frontend) add AI to the project #321 +``` + +## Pull Requests + +It is nice to add information about the purpose of the pull request to help reviewers understand the context and intent of the changes. If you can, add some pictures or a small video to show the changes. + +### Don't forget to: +- signoff your commits +- sign your commits with your key (SSH, GPG etc.) +- check your commits (see warnings above) +- check the linting: `make lint && make frontend-lint` +- check the tests: `make test` +- add a changelog entry + +Once all the required tests have passed, you can request a review from the project maintainers. + +## Code Style + +Please maintain consistency in code style. Run any linting tools available to make sure the code is clean and follows the project's conventions. + +## Tests + +Make sure that all new features or fixes have corresponding tests. Run the test suite before pushing your changes to ensure that nothing is broken. + +## Asking for Help + +If you need any help while contributing, feel free to open a discussion or ask for guidance in the issue tracker. We are more than happy to assist! + +Thank you for your contributions! 👍 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a9dffdd --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Agence Nationale de la Cohésion des Territoires - Gouvernement Français + +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. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..03cfe21 --- /dev/null +++ b/Makefile @@ -0,0 +1,369 @@ +# /!\ /!\ /!\ /!\ /!\ /!\ /!\ DISCLAIMER /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ +# +# This Makefile is only meant to be used for DEVELOPMENT purpose as we are +# changing the user id that will run in the container. +# +# PLEASE DO NOT USE IT FOR YOUR CI/PRODUCTION/WHATEVER... +# +# /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ /!\ +# +# Note to developers: +# +# While editing this file, please respect the following statements: +# +# 1. Every variable should be defined in the ad hoc VARIABLES section with a +# relevant subsection +# 2. Every new rule should be defined in the ad hoc RULES section with a +# relevant subsection depending on the targeted service +# 3. Rules should be sorted alphabetically within their section +# 4. When a rule has multiple dependencies, you should: +# - duplicate the rule name to add the help string (if required) +# - write one dependency per line to increase readability and diffs +# 5. .PHONY rule statement should be written after the corresponding rule +# ============================================================================== +# VARIABLES + +BOLD := \033[1m +RESET := \033[0m +GREEN := \033[1;32m + + +# -- Database + +DB_HOST = postgresql +DB_PORT = 5432 + +# -- Docker +# Get the current user ID to use for docker run and docker exec commands +DOCKER_UID = $(shell id -u) +DOCKER_GID = $(shell id -g) +DOCKER_USER = $(DOCKER_UID):$(DOCKER_GID) +COMPOSE = DOCKER_USER=$(DOCKER_USER) docker compose +COMPOSE_EXEC = $(COMPOSE) exec +COMPOSE_EXEC_APP = $(COMPOSE_EXEC) backend-dev +COMPOSE_RUN = $(COMPOSE) run --rm +COMPOSE_RUN_APP = $(COMPOSE_RUN) backend-dev +COMPOSE_RUN_APP_NO_DEPS = $(COMPOSE_RUN) --no-deps backend-dev + +COMPOSE_RUN_CROWDIN = $(COMPOSE_RUN) crowdin crowdin + +# -- Backend +MANAGE = $(COMPOSE_RUN_APP) python manage.py +MANAGE_EXEC = $(COMPOSE_EXEC_APP) python manage.py +PSQL_E2E = ./bin/postgres_e2e + +# -- Frontend +PATH_FRONT = ./src/frontend +PATH_FRONT_CALENDARS = $(PATH_FRONT)/apps/calendars + +# ============================================================================== +# RULES + +default: help + +data/media: + @mkdir -p data/media + +data/static: + @mkdir -p data/static + +# -- Project + +create-env-files: ## Create empty .local env files for local development +create-env-files: \ + env.d/development/crowdin.local \ + env.d/development/postgresql.local \ + env.d/development/keycloak.local \ + env.d/development/backend.local \ + env.d/development/frontend.local \ + env.d/development/davical.local +.PHONY: create-env-files + +env.d/development/%.local: + @echo "# Local development overrides for $(notdir $*)" > $@ + @echo "# Add your local-specific environment variables below:" >> $@ + @echo "# Example: DJANGO_DEBUG=True" >> $@ + @echo "" >> $@ +.PHONY: env.d/development/%.local + +create-docker-network: ## create the docker network if it doesn't exist + @docker network create lasuite-network || true +.PHONY: create-docker-network + +bootstrap: ## Prepare Docker images for the project +bootstrap: \ + data/media \ + data/static \ + create-env-files \ + build \ + create-docker-network \ + migrate \ + migrate-davical \ + back-i18n-compile \ + run +.PHONY: bootstrap + +# -- Docker/compose +build: cache ?= # --no-cache +build: ## build the project containers + @$(MAKE) build-backend cache=$(cache) + @$(MAKE) build-frontend cache=$(cache) +.PHONY: build + +build-backend: cache ?= +build-backend: ## build the backend-dev container + @$(COMPOSE) build backend-dev $(cache) +.PHONY: build-backend + +build-frontend: cache ?= +build-frontend: ## build the frontend container + @$(COMPOSE) build frontend-dev $(cache) +.PHONY: build-frontend-development + +down: ## stop and remove containers, networks, images, and volumes + @$(COMPOSE) down + rm -rf data/postgresql.* +.PHONY: down + +logs: ## display backend-dev logs (follow mode) + @$(COMPOSE) logs -f backend-dev +.PHONY: logs + +run-backend: ## start the backend container + @$(COMPOSE) up --force-recreate -d celery-dev + @$(COMPOSE) up --force-recreate -d nginx +.PHONY: run-backend + +bootstrap-e2e: ## bootstrap the backend container for e2e tests, without frontend +bootstrap-e2e: \ + data/media \ + data/static \ + create-env-local-files \ + build-backend \ + create-docker-network \ + back-i18n-compile \ + run-backend-e2e +.PHONY: bootstrap-e2e + +clear-db-e2e: ## quickly clears the database for e2e tests, used in the e2e tests + $(PSQL_E2E) -c "$$(cat bin/clear_db_e2e.sql)" +.PHONY: clear-db-e2e + +run-backend-e2e: ## start the backend container for e2e tests, always remove the postgresql.e2e volume first + @$(MAKE) stop + rm -rf data/postgresql.e2e + @ENV_OVERRIDE=e2e $(MAKE) run-backend + @ENV_OVERRIDE=e2e $(MAKE) migrate +.PHONY: run-backend-e2e + +run-tests-e2e: ## run the e2e tests, example: make run-tests-e2e -- --project chromium --headed + @$(MAKE) run-backend-e2e + @args="$(filter-out $@,$(MAKECMDGOALS))" && \ + cd src/frontend/apps/e2e && yarn test $${args:-${1}} +.PHONY: run-tests-e2e + +backend-exec-command: ## execute a command in the backend container + @args="$(filter-out $@,$(MAKECMDGOALS))" && \ + $(MANAGE_EXEC) $${args} +.PHONY: backend-exec-command + +run: ## start the development server and frontend development +run: + @$(MAKE) run-backend + @$(COMPOSE) up --force-recreate -d frontend-dev + +migrate-davical: ## Initialize DAViCal database schema + @echo "$(BOLD)Initializing DAViCal database schema...$(RESET)" + @$(COMPOSE) run --rm davical run-migrations + @echo "$(GREEN)DAViCal initialized$(RESET)" +.PHONY: migrate-davical + +status: ## an alias for "docker compose ps" + @$(COMPOSE) ps +.PHONY: status + +stop: ## stop the development server using Docker + @$(COMPOSE) stop +.PHONY: stop + +# -- Backend + +demo: ## flush db then create a demo for load testing purpose + @$(MAKE) resetdb + @$(MANAGE) create_demo +.PHONY: demo + +index: ## index all files to remote search + @$(MANAGE) index +.PHONY: index + +# Nota bene: Black should come after isort just in case they don't agree... +lint: ## lint back-end python sources +lint: \ + lint-ruff-format \ + lint-ruff-check \ + lint-pylint +.PHONY: lint + +lint-ruff-format: ## format back-end python sources with ruff + @echo 'lint:ruff-format started…' + @$(COMPOSE_RUN_APP_NO_DEPS) ruff format . +.PHONY: lint-ruff-format + +lint-ruff-check: ## lint back-end python sources with ruff + @echo 'lint:ruff-check started…' + @$(COMPOSE_RUN_APP_NO_DEPS) ruff check . --fix +.PHONY: lint-ruff-check + +lint-pylint: ## lint back-end python sources with pylint only on changed files from main + @echo 'lint:pylint started…' + bin/pylint --diff-only=origin/main +.PHONY: lint-pylint + +test: ## run project tests + @$(MAKE) test-back-parallel +.PHONY: test + +test-back: ## run back-end tests + @args="$(filter-out $@,$(MAKECMDGOALS))" && \ + bin/pytest $${args:-${1}} +.PHONY: test-back + +test-back-parallel: ## run all back-end tests in parallel + @args="$(filter-out $@,$(MAKECMDGOALS))" && \ + bin/pytest -n auto $${args:-${1}} +.PHONY: test-back-parallel + +makemigrations: ## run django makemigrations for the calendar project. + @echo "$(BOLD)Running makemigrations$(RESET)" + @$(COMPOSE) up -d postgresql + @$(MANAGE) makemigrations +.PHONY: makemigrations + +migrate: ## run django migrations for the calendar project. + @echo "$(BOLD)Running migrations$(RESET)" + @$(COMPOSE) up -d postgresql + @$(MANAGE) migrate +.PHONY: migrate + +superuser: ## Create an admin superuser with password "admin" + @echo "$(BOLD)Creating a Django superuser$(RESET)" + @$(MANAGE) createsuperuser --email admin@example.com --password admin +.PHONY: superuser + + +back-i18n-compile: ## compile the gettext files + @$(MANAGE) compilemessages --ignore=".venv/**/*" +.PHONY: back-i18n-compile + +back-lock: ## regenerate the uv.lock file (uses temporary container) + @echo "$(BOLD)Regenerating uv.lock$(RESET)" + @docker run --rm -v $(PWD)/src/backend:/app -w /app ghcr.io/astral-sh/uv:python3.13-alpine uv lock +.PHONY: back-lock + +back-i18n-generate: ## create the .pot files used for i18n + @$(MANAGE) makemessages -a --keep-pot --all +.PHONY: back-i18n-generate + +back-shell: ## open a shell in the backend container + @$(COMPOSE) run --rm --build backend-dev /bin/sh +.PHONY: back-shell + +shell: ## connect to django shell + @$(MANAGE) shell #_plus +.PHONY: shell + +# -- Database + +dbshell: ## connect to database shell + docker compose exec backend-dev python manage.py dbshell +.PHONY: dbshell + +resetdb: FLUSH_ARGS ?= +resetdb: ## flush database and create a superuser "admin" + @echo "$(BOLD)Flush database$(RESET)" + @$(MANAGE) flush $(FLUSH_ARGS) + @${MAKE} superuser +.PHONY: resetdb + +# -- Internationalization + +crowdin-download: ## Download translated message from crowdin + @$(COMPOSE_RUN_CROWDIN) download -c crowdin/config.yml +.PHONY: crowdin-download + +crowdin-download-sources: ## Download sources from Crowdin + @$(COMPOSE_RUN_CROWDIN) download sources -c crowdin/config.yml +.PHONY: crowdin-download-sources + +crowdin-upload: ## Upload source translations to crowdin + @$(COMPOSE_RUN_CROWDIN) upload sources -c crowdin/config.yml +.PHONY: crowdin-upload + +i18n-compile: ## compile all translations +i18n-compile: \ + back-i18n-compile \ + frontend-i18n-compile +.PHONY: i18n-compile + +i18n-generate: ## create the .pot files and extract frontend messages +i18n-generate: \ + back-i18n-generate \ + frontend-i18n-generate +.PHONY: i18n-generate + +i18n-download-and-compile: ## download all translated messages and compile them to be used by all applications +i18n-download-and-compile: \ + crowdin-download \ + i18n-compile +.PHONY: i18n-download-and-compile + +i18n-generate-and-upload: ## generate source translations for all applications and upload them to Crowdin +i18n-generate-and-upload: \ + i18n-generate \ + crowdin-upload +.PHONY: i18n-generate-and-upload + + +# -- Misc +clean: ## restore repository state as it was freshly cloned + git clean -idx +.PHONY: clean + +clean-media: ## remove all media files + rm -rf data/media/* +.PHONY: clean-media + +help: + @echo "$(BOLD)calendar Makefile" + @echo "Please use 'make $(BOLD)target$(RESET)' where $(BOLD)target$(RESET) is one of:" + @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(firstword $(MAKEFILE_LIST)) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "$(GREEN)%-30s$(RESET) %s\n", $$1, $$2}' +.PHONY: help + +# Front +frontend-development-install: ## install the frontend locally + cd $(PATH_FRONT_CALENDARS) && yarn +.PHONY: frontend-development-install + +frontend-lint: ## run the frontend linter + cd $(PATH_FRONT) && yarn lint +.PHONY: frontend-lint + +run-frontend-development: ## Run the frontend in development mode + @$(COMPOSE) stop frontend-dev + cd $(PATH_FRONT_CALENDARS) && yarn dev +.PHONY: run-frontend-development + +frontend-i18n-extract: ## Extract the frontend translation inside a json to be used for crowdin + cd $(PATH_FRONT) && yarn i18n:extract +.PHONY: frontend-i18n-extract + +frontend-i18n-generate: ## Generate the frontend json files used for crowdin +frontend-i18n-generate: \ + crowdin-download-sources \ + frontend-i18n-extract +.PHONY: frontend-i18n-generate + +frontend-i18n-compile: ## Format the crowin json files used deploy to the apps + cd $(PATH_FRONT) && yarn i18n:deploy +.PHONY: frontend-i18n-compile diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..700057e --- /dev/null +++ b/Procfile @@ -0,0 +1,3 @@ +web: bin/scalingo_run_web +worker: celery -A calendars.celery_app worker --task-events --beat -l INFO -c $DJANGO_CELERY_CONCURRENCY -Q celery,default +postdeploy: python manage.py migrate diff --git a/README.md b/README.md new file mode 100644 index 0000000..d51a531 --- /dev/null +++ b/README.md @@ -0,0 +1,155 @@ +

+ + Calendars banner + +

+

+ GitHub commit activity + GitHub closed issues + + GitHub closed issues + +

+ +

+ + Chat on Matrix + - + Documentation + - + Getting started + - + Reach out + +

+ +# La Suite Calendars +A modern calendar application for managing events and schedules. + + + + +## Why use Calendars ❓ +Calendars empowers teams to manage events and schedules while maintaining full control over their data through a user-friendly, open-source platform. + +### Manage Events +- 📅 Create and manage events and schedules +- 🌐 Access your calendar from anywhere with our web-based interface + +### Organize +- 📂 Organized calendar structure with intuitive navigation + +### Collaborate +- 🤝 Share calendars with your team members +- 👥 Granular access control to ensure your information is secure and only shared with the right people +- 🏢 Create workspaces to organize team collaboration + +### Self-host +* 🚀 Easy to install, scalable and secure calendar solution + +## Getting started 🔧 + +### Prerequisite + +Make sure you have a recent version of Docker and [Docker +Compose](https://docs.docker.com/compose/install) installed on your laptop: + +```bash +$ docker -v + Docker version 27.5.1, build 9f9e405 + +$ docker compose version + Docker Compose version v2.32.4 +``` + +> ⚠️ You may need to run the following commands with `sudo` but this can be +> avoided by assigning your user to the `docker` group. + +### Bootstrap project + +The easiest way to start working on the project is to use GNU Make: + +```bash +$ make bootstrap +``` + +This command builds the `backend-dev` and `frontend-dev` containers, installs dependencies, performs +database migrations and compile translations. It's a good idea to use this +command each time you are pulling code from the project repository to avoid +dependency-related or migration-related issues. + +Your Docker services should now be up and running! 🎉 + +You can access the project by going to . + +You will be prompted to log in. The default credentials are: + +``` +username: calendars +password: calendars +``` + +Note that if you need to run them afterward, you can use the eponym Make rule: + +```bash +$ make run +``` + +You can check all available Make rules using: + +```bash +$ make help +``` + +⚠️ For the frontend developer, it is often better to run the frontend in development mode locally. + +To do so, install the frontend dependencies with the following command: + +```shellscript +$ make frontend-development-install +``` + +And run the frontend locally in development mode with the following command: + +```shellscript +$ make run-frontend-development +``` + +To start all the services, except the frontend container, you can use the following command: + +```shellscript +$ make run-backend +``` + +### Django admin + +You can access the Django admin site at +[http://localhost:8921/admin](http://localhost:8921/admin). + +You first need to create a superuser account: + +```bash +$ make superuser +``` + +You can then login with sub `admin@example.com` and password `admin`. + + +## Feedback 🙋‍♂️🙋‍♀️ + +We'd love to hear your thoughts and hear about your experiments, so come and say hi on [Matrix](https://matrix.to/#/#messages-official:matrix.org). + +## Contributing 🙌 + +This project is intended to be community-driven, so please, do not hesitate to get in touch if you have any question related to our implementation or design +decisions. + +## License 📝 + +This work is released under the MIT License (see [LICENSE](./LICENSE)). + +While Calendars is a public driven initiative our licence choice is an invitation for private sector actors to use, sell and contribute to the project. + +## Credits ❤️ + +Calendars is built on top of [Django Rest Framework](https://www.django-rest-framework.org/), [Next.js](https://nextjs.org/). We thank the contributors of all these projects for their awesome work! diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..7a4d5ba --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Reporting a Vulnerability + +Security is very important to us. + +If you have any issue regarding security, please disclose the information responsibly emailing us at security@suite.anct.gouv.fr + +We appreciate your effort to make Calendars more secure. + +## Vulnerability disclosure policy + +Working with security issues in an open source project can be challenging, as we are required to disclose potential problems that could be exploited by attackers. With this in mind, our security fix policy is as follows: + +1. The Maintainers team will handle the fix as usual (Pull Request, +release). +2. In the release notes, we will include the identification numbers from the +GitHub Advisory Database (GHSA) and, if applicable, the Common Vulnerabilities +and Exposures (CVE) identifier for the vulnerability. +3. Once this grace period has passed, we will publish the vulnerability. + +By adhering to this security policy, we aim to address security concerns +effectively and responsibly in our open source software project. \ No newline at end of file diff --git a/bin/_config.sh b/bin/_config.sh new file mode 100644 index 0000000..071f9d3 --- /dev/null +++ b/bin/_config.sh @@ -0,0 +1,93 @@ +#!/usr/bin/env bash + +set -eo pipefail + +REPO_DIR="$(cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd)" +UNSET_USER=0 + +if [ -z ${COMPOSE_FILE+x} ]; then + COMPOSE_FILE="${REPO_DIR}/compose.yaml" +fi + +# _set_user: set (or unset) default user id used to run docker commands +# +# usage: _set_user +# +# You can override default user ID (the current host user ID), by defining the +# USER_ID environment variable. +# +# To avoid running docker commands with a custom user, please set the +# $UNSET_USER environment variable to 1. +function _set_user() { + + if [ $UNSET_USER -eq 1 ]; then + USER_ID="" + return + fi + + # USER_ID = USER_ID or `id -u` if USER_ID is not set + USER_ID=${USER_ID:-$(id -u)} + + echo "🙋(user) ID: ${USER_ID}" +} + +# docker_compose: wrap docker compose command +# +# usage: docker_compose [options] [ARGS...] +# +# options: docker compose command options +# ARGS : docker compose command arguments +function _docker_compose() { + + echo "🐳(compose) project, file: '${COMPOSE_FILE}'" + docker compose \ + -f "${COMPOSE_FILE}" \ + --project-directory "${REPO_DIR}" \ + "$@" +} + +# _dc_run: wrap docker compose run command +# +# usage: _dc_run [options] [ARGS...] +# +# options: docker compose run command options +# ARGS : docker compose run command arguments +function _dc_run() { + _set_user + + user_args="--user=$USER_ID" + if [ -z $USER_ID ]; then + user_args="" + fi + + _docker_compose run --rm $user_args "$@" +} + +# _dc_exec: wrap docker compose exec command +# +# usage: _dc_exec [options] [ARGS...] +# +# options: docker compose exec command options +# ARGS : docker compose exec command arguments +function _dc_exec() { + _set_user + + echo "🐳(compose) exec command: '\$@'" + + user_args="--user=$USER_ID" + if [ -z $USER_ID ]; then + user_args="" + fi + + _docker_compose exec $user_args "$@" +} + +# _django_manage: wrap django's manage.py command with docker compose +# +# usage : _django_manage [ARGS...] +# +# ARGS : django's manage.py command arguments +function _django_manage() { + _dc_run "backend-dev" python manage.py "$@" +} + diff --git a/bin/clear_db_e2e.sql b/bin/clear_db_e2e.sql new file mode 100644 index 0000000..6a2c0a1 --- /dev/null +++ b/bin/clear_db_e2e.sql @@ -0,0 +1,9 @@ +DO $$ +DECLARE r RECORD; +BEGIN + FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = 'public' AND tablename != 'django_migrations') + LOOP + RAISE NOTICE 'Truncating table %', r.tablename; + EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || ' CASCADE'; + END LOOP; +END $$; diff --git a/bin/compose b/bin/compose new file mode 100755 index 0000000..1adb3d8 --- /dev/null +++ b/bin/compose @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# shellcheck source=bin/_config.sh +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +_docker_compose "$@" diff --git a/bin/fernetkey b/bin/fernetkey new file mode 100755 index 0000000..92b6b4c --- /dev/null +++ b/bin/fernetkey @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# shellcheck source=bin/_config.sh +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +_dc_run backend-dev python -c 'from cryptography.fernet import Fernet;import sys; sys.stdout.write("\n" + Fernet.generate_key().decode() + "\n");' diff --git a/bin/manage b/bin/manage new file mode 100755 index 0000000..b6c82d9 --- /dev/null +++ b/bin/manage @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +# shellcheck source=bin/_config.sh +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +_django_manage "$@" diff --git a/bin/postgres_e2e b/bin/postgres_e2e new file mode 100755 index 0000000..8d2f6e4 --- /dev/null +++ b/bin/postgres_e2e @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +# shellcheck source=bin/_config.sh +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +# Get database credentials from environment file +ENV_FILE="${REPO_DIR}/env.d/development/postgresql.e2e" +POSTGRES_USER=$(grep POSTGRES_USER "$ENV_FILE" | cut -d'=' -f2) +POSTGRES_DB=$(grep POSTGRES_DB "$ENV_FILE" | cut -d'=' -f2) + +# Execute PostgreSQL command (run as postgres user, not host user) +_docker_compose exec -T postgresql psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -v ON_ERROR_STOP=1 "$@" diff --git a/bin/pylint b/bin/pylint new file mode 100755 index 0000000..f58bdb8 --- /dev/null +++ b/bin/pylint @@ -0,0 +1,38 @@ +#!/usr/bin/env bash + +# shellcheck source=bin/_config.sh +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +declare diff_from +declare -a paths +declare -a args + +# Parse options +for arg in "$@" +do + case $arg in + --diff-only=*) + diff_from="${arg#*=}" + shift + ;; + -*) + args+=("$arg") + shift + ;; + *) + paths+=("$arg") + shift + ;; + esac +done + +if [[ -n "${diff_from}" ]]; then + # Run pylint only on modified files located in src/backend + # (excluding deleted files and migration files) + # shellcheck disable=SC2207 + paths=($(git diff "${diff_from}" --name-only --diff-filter=d -- src/backend ':!**/migrations/*.py' | grep -E '^src/backend/.*\.py$')) +fi + +# Fix docker vs local path when project sources are mounted as a volume +read -ra paths <<< "$(echo "${paths[@]}" | sed "s|src/backend/||g")" +_dc_run --no-deps backend-dev pylint "${paths[@]}" "${args[@]}" diff --git a/bin/pytest b/bin/pytest new file mode 100755 index 0000000..bd3b0d1 --- /dev/null +++ b/bin/pytest @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +_dc_run \ + -e DJANGO_CONFIGURATION=Test \ + backend-dev \ + pytest "$@" diff --git a/bin/scalingo_postcompile b/bin/scalingo_postcompile new file mode 100644 index 0000000..425f8c0 --- /dev/null +++ b/bin/scalingo_postcompile @@ -0,0 +1,11 @@ +#!/bin/bash + +set -o errexit # always exit on error +set -o pipefail # don't ignore exit codes when piping output + +echo "-----> Running post-compile script" + +# Remove all the files we don't need +rm -rf src docker env.d .cursor .github compose.yaml README.md .cache + +chmod +x bin/scalingo_run_web diff --git a/bin/scalingo_postfrontend b/bin/scalingo_postfrontend new file mode 100644 index 0000000..6036678 --- /dev/null +++ b/bin/scalingo_postfrontend @@ -0,0 +1,15 @@ +#!/bin/bash + +set -o errexit # always exit on error +set -o pipefail # don't ignore exit codes when piping output + +echo "-----> Running post-frontend script" + +# Move the frontend build to the nginx root and clean up +mkdir -p build/ +mv src/frontend/apps/calendars/out build/frontend-out + +mv src/backend/* ./ +mv src/nginx/* ./ + +echo "3.13" > .python-version diff --git a/bin/scalingo_run_web b/bin/scalingo_run_web new file mode 100644 index 0000000..cac67f4 --- /dev/null +++ b/bin/scalingo_run_web @@ -0,0 +1,15 @@ +#!/bin/bash + +# Start the Django backend +gunicorn -b :8000 calendars.wsgi:application --log-file - & + +# Start the Nginx server +bin/run & + +# if the current shell is killed, also terminate all its children +trap "pkill SIGTERM -P $$" SIGTERM + +# wait for a single child to finish, +wait -n +# then kill all the other tasks +pkill -P $$ diff --git a/bin/update_app_cacert.sh b/bin/update_app_cacert.sh new file mode 100755 index 0000000..4011503 --- /dev/null +++ b/bin/update_app_cacert.sh @@ -0,0 +1,17 @@ +#!/bin/sh +set -o errexit + +# The script is pretty simple. It downloads the latest cacert.pem file from the certifi package and appends the root certificate from mkcert to it. Then it copies the updated cacert.pem file to the container. +# The script is executed with the following command: +# $ bin/update_app_cacert.sh docs-production-backend-1 + +CONTAINER_NAME=${1:-"calendars-production-backend-1"} + +echo "updating cacert.pem for certifi package in ${CONTAINER_NAME}" + + +curl --create-dirs https://raw.githubusercontent.com/certifi/python-certifi/refs/heads/master/certifi/cacert.pem -o /tmp/certifi/cacert.pem +cat "$(mkcert -CAROOT)/rootCA.pem" >> /tmp/certifi/cacert.pem +docker cp /tmp/certifi/cacert.pem ${CONTAINER_NAME}:/usr/local/lib/python3.12/site-packages/certifi/cacert.pem + +echo "end patching cacert.pem in ${CONTAINER_NAME}" diff --git a/bin/update_openapi_schema b/bin/update_openapi_schema new file mode 100755 index 0000000..ac28aa5 --- /dev/null +++ b/bin/update_openapi_schema @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +source "$(dirname "${BASH_SOURCE[0]}")/_config.sh" + +_dc_run \ + -e DJANGO_CONFIGURATION=Test \ + backend-dev \ + python manage.py spectacular \ + --api-version 'v1.0' \ + --urlconf 'calendars.api_urls' \ + --format openapi-json \ + --file /app/core/tests/swagger/swagger.json diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..d7f8daa --- /dev/null +++ b/compose.yaml @@ -0,0 +1,183 @@ +name: calendars + +services: + # Shared PostgreSQL for all services (calendar, davical, keycloak) + postgresql: + image: postgres:15 + ports: + - "8912:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"] + interval: 1s + timeout: 2s + retries: 300 + env_file: + - env.d/development/postgresql.defaults + - env.d/development/postgresql.local + + redis: + image: redis:5 + ports: + - "6379:6379" + + mailcatcher: + image: sj26/mailcatcher:latest + ports: + - "1081:1080" + + backend-dev: + build: + context: src/backend + target: backend-development + args: + DOCKER_USER: ${DOCKER_USER:-1000} + user: ${DOCKER_USER:-1000} + image: calendars:backend-development + environment: + - PYLINTHOME=/app/.pylint.d + - DJANGO_CONFIGURATION=Development + - DAVICAL_URL=http://davical:80 + env_file: + - env.d/development/backend.defaults + - env.d/development/backend.local + ports: + - "8921:8000" + volumes: + - ./src/backend:/app + - ./data/static:/data/static + - /app/.venv + networks: + - lasuite + - default + depends_on: + postgresql: + condition: service_healthy + restart: true + mailcatcher: + condition: service_started + redis: + condition: service_started + celery-dev: + condition: service_started + davical: + condition: service_started + + celery-dev: + user: ${DOCKER_USER:-1000} + image: calendars:backend-development + networks: + - default + - lasuite + command: ["celery", "-A", "calendars.celery_app", "worker", "-l", "DEBUG"] + environment: + - DJANGO_CONFIGURATION=Development + env_file: + - env.d/development/backend.defaults + - env.d/development/backend.local + volumes: + - ./src/backend:/app + - ./data/static:/data/static + - /app/.venv + + nginx: + image: nginx:1.25 + ports: + - "8923:8083" + networks: + default: {} + lasuite: + aliases: + - nginx + volumes: + - ./docker/files/development/etc/nginx/conf.d:/etc/nginx/conf.d:ro + depends_on: + - keycloak + - backend-dev + + frontend-dev: + user: "${DOCKER_USER:-1000}" + build: + context: src/frontend + target: calendars-dev + args: + API_ORIGIN: "http://localhost:8921" + image: calendars:frontend-development + env_file: + - env.d/development/frontend.defaults + - env.d/development/frontend.local + volumes: + - ./src/frontend/:/home/frontend/ + - /home/frontend/node_modules + - /home/frontend/apps/calendars/node_modules + - /home/frontend/packages/open-calendar/dist + - /home/frontend/packages/open-calendar/node_modules + ports: + - "8920:3000" + + crowdin: + image: crowdin/cli:3.16.0 + volumes: + - ".:/app" + env_file: + - env.d/development/crowdin.defaults + - env.d/development/crowdin.local + user: "${DOCKER_USER:-1000}" + working_dir: /app + + node: + image: node:22 + user: "${DOCKER_USER:-1000}" + environment: + HOME: /tmp + volumes: + - ".:/app" + + # DAViCal CalDAV Server + davical: + image: fintechstudios/davical:latest + platform: linux/amd64 + ports: + - "8922:80" + env_file: + - env.d/development/davical.defaults + - env.d/development/davical.local + volumes: + # Mount our custom config.php if we need to override defaults + - ./docker/davical/config.php:/etc/davical/config.php:ro + - ./docker/davical/run-migrations:/usr/local/bin/run-migrations:ro + networks: + - default + - lasuite + depends_on: + postgresql: + condition: service_healthy + + # Keycloak - now using shared PostgreSQL + keycloak: + image: quay.io/keycloak/keycloak:26.3.2 + volumes: + - ./docker/auth/realm.json:/opt/keycloak/data/import/realm.json + command: + - start-dev + - --features=preview + - --import-realm + - --hostname=http://localhost:8925 + - --hostname-strict=false + env_file: + - env.d/development/keycloak.defaults + - env.d/development/keycloak.local + ports: + - "8925:8080" + depends_on: + postgresql: + condition: service_healthy + networks: + - lasuite + - default + +networks: + default: {} + lasuite: + name: lasuite-network + driver: bridge + external: true diff --git a/cron.json b/cron.json new file mode 100644 index 0000000..61675d3 --- /dev/null +++ b/cron.json @@ -0,0 +1,7 @@ +{ + "jobs": [ + { + "command": "0 0 * * * bin/scalingo_pgdump.sh" + } + ] +} diff --git a/docker/auth/realm.json b/docker/auth/realm.json new file mode 100644 index 0000000..13cd002 --- /dev/null +++ b/docker/auth/realm.json @@ -0,0 +1,2358 @@ +[ + { + "realm": "master", + "sslRequired": "none", + "enabled": true + }, + { + "id": "ccf4fd40-4286-474d-854a-4714282a8bec", + "realm": "calendars", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "none", + "registrationAllowed": true, + "registrationEmailAsUsername": false, + "rememberMe": true, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": true, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "users": [ + { + "username": "calendars", + "email": "calendars@calendars.world", + "firstName": "John", + "lastName": "Doe", + "enabled": true, + "credentials": [ + { + "type": "password", + "value": "calendars" + } + ], + "realmRoles": ["user"] + }, + { + "username": "user-e2e-chromium", + "email": "user@chromium.test", + "firstName": "E2E", + "lastName": "Chromium", + "enabled": true, + "credentials": [ + { + "type": "password", + "value": "password-e2e-chromium" + } + ], + "realmRoles": ["user"] + }, + { + "username": "user-e2e-webkit", + "email": "user@webkit.test", + "firstName": "E2E", + "lastName": "Webkit", + "enabled": true, + "credentials": [ + { + "type": "password", + "value": "password-e2e-webkit" + } + ], + "realmRoles": ["user"] + }, + { + "username": "user-e2e-firefox", + "email": "user@firefox.test", + "firstName": "E2E", + "lastName": "Firefox", + "enabled": true, + "credentials": [ + { + "type": "password", + "value": "password-e2e-firefox" + } + ], + "realmRoles": ["user"] + } + ], + "roles": { + "realm": [ + { + "id": "1f116065-05b6-4269-80a6-c7d904b584b7", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "ccf4fd40-4286-474d-854a-4714282a8bec", + "attributes": {} + }, + { + "id": "1bfe401a-08fc-4d94-80e0-86c4f5195f99", + "name": "default-roles-calendars", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "realm": ["offline_access", "uma_authorization"], + "client": { + "account": ["view-profile", "manage-account"] + } + }, + "clientRole": false, + "containerId": "ccf4fd40-4286-474d-854a-4714282a8bec", + "attributes": {} + }, + { + "id": "8733db03-278a-45ad-a25e-c167fbd95b5a", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "ccf4fd40-4286-474d-854a-4714282a8bec", + "attributes": {} + } + ], + "client": { + "realm-management": [ + { + "id": "9dcc0883-e2e5-4671-9159-402bdbe73c57", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "ae911be0-ea2e-466d-93e0-f8e73fa8f444", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "e777d332-7205-4b76-8b21-9191a2e85a0d", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "b1a95608-d518-4ede-936e-525ab704d363", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "ac58976a-ae55-4d92-a864-b33e21b07c54", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "a149b28f-d252-4ceb-8ba9-8161603c4184", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "00a5b886-7ca4-4fba-90c6-a9071e697d86", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "b22d5cc1-879e-4405-8345-cc204fd0fec0", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "impersonation", + "view-authorization", + "manage-authorization", + "create-client", + "view-events", + "manage-identity-providers", + "manage-clients", + "view-identity-providers", + "query-users", + "manage-users", + "view-clients", + "view-users", + "manage-events", + "view-realm", + "query-realms", + "query-groups", + "manage-realm", + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "b3e9faf6-17bf-4f62-abd5-07837806a7e6", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "a8d85f42-023b-48dd-8f49-c9da2b5317ee", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "eb325a4d-db7a-4f6a-a88b-0ff8aa38b0a5", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "267bb612-62f4-4354-abb2-ac6a34bd854b", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-clients"] + } + }, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "b575be2b-e250-4000-b75e-3038cda8c0dd", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "e19cd0bf-8da0-457d-b630-454c611bc1ba", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": ["query-users", "query-groups"] + } + }, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "c12145cc-cbdc-4ef3-9774-19b1852811ba", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "e7e15b84-4971-4c13-be93-315bb36d30e1", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "e03d2989-a620-4918-85ed-3eabd0373bb4", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "daf8d347-4b30-41d6-a431-7b3723dd8e6f", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + }, + { + "id": "432cd3eb-4741-46ba-938a-94ff9dece315", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "attributes": {} + } + ], + "security-admin-console": [], + "admin-cli": [], + "account-console": [], + "broker": [ + { + "id": "2e713186-38da-44d7-a5a5-19d91ef2dfca", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "41dd8f26-46c2-471a-859e-01886f972ff9", + "attributes": {} + } + ], + "calendars": [], + "account": [ + { + "id": "63b1a4e1-a594-4571-99c3-7c5c3efd61ce", + "name": "manage-consent", + "description": "${role_manage-consent}", + "composite": true, + "composites": { + "client": { + "account": ["view-consent"] + } + }, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "36ef5fd6-1167-4ba0-9171-c8cb6cfe904b", + "name": "view-groups", + "description": "${role_view-groups}", + "composite": false, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "f984654a-fca5-45d9-bb47-73009eb9bcf0", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "d54168c5-58a5-4f13-9fa8-6dbbee0e4b73", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": ["manage-account-links"] + } + }, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "092b6808-1ee2-44be-9b5d-085ccd6862b4", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "ddd57af0-2a5e-4f9d-98e5-ec96c8d852ce", + "name": "view-applications", + "description": "${role_view-applications}", + "composite": false, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "84c7324a-4724-41fe-8bd4-848ce5cebd5b", + "name": "view-consent", + "description": "${role_view-consent}", + "composite": false, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + }, + { + "id": "20d06f75-ea65-4b99-b9ef-2384ffd1de53", + "name": "delete-account", + "description": "${role_delete-account}", + "composite": false, + "clientRole": true, + "containerId": "06721011-1061-4ca7-944f-be2a20719e20", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRole": { + "id": "1bfe401a-08fc-4d94-80e0-86c4f5195f99", + "name": "default-roles-calendars", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "ccf4fd40-4286-474d-854a-4714282a8bec" + }, + "requiredCredentials": ["password"], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpPolicyCodeReusable": false, + "otpSupportedApplications": ["totpAppGoogleName", "totpAppFreeOTPName"], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": ["ES256"], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": ["ES256"], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": ["offline_access"] + } + ], + "clientScopeMappings": { + "account": [ + { + "client": "account-console", + "roles": ["manage-account", "view-groups"] + } + ] + }, + "clients": [ + { + "id": "06721011-1061-4ca7-944f-be2a20719e20", + "clientId": "account", + "name": "${client_account}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/calendars/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/calendars/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "987e14a5-caed-40a6-8bac-8c429b74ca48", + "clientId": "account-console", + "name": "${client_account-console}", + "rootUrl": "${authBaseUrl}", + "baseUrl": "/realms/calendars/account/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/realms/calendars/account/*"], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "4f958126-eaa1-46d5-967a-3a3c2e2d11f7", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "92da37ad-e8a1-41f1-93c6-541dffa7d601", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "41dd8f26-46c2-471a-859e-01886f972ff9", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "869481d0-5774-4e64-bc30-fedc7c58958f", + "clientId": "calendars", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "ThisIsAnExampleKeyForDevPurposeOnly", + "redirectUris": [ + "http://localhost:8920/*", + "http://localhost:8921/*", + "http://localhost:8922/*", + "http://localhost:8923/*" + ], + "webOrigins": [ + "http://localhost:8920", + "http://localhost:8921", + "http://localhost:8922", + "http://localhost:8923" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "access.token.lifespan": "-1", + "client.secret.creation.time": "1707820779", + "user.info.response.signature.alg": "RS256", + "post.logout.redirect.uris": "http://localhost:8920/*##http://localhost:8921/*", + "oauth2.device.authorization.grant.enabled": "false", + "use.jwks.url": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "use.refresh.tokens": "true", + "tls-client-certificate-bound-access-tokens": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "acr.loa.map": "{}", + "require.pushed.authorization.requests": "false", + "display.on.consent.screen": "false", + "client.session.idle.timeout": "-1", + "token.response.type.bearer.lower-case": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "869481d0-5774-4e64-bc30-fedc7c58958g", + "clientId": "deploycenter", + "name": "", + "description": "", + "rootUrl": "", + "adminUrl": "", + "baseUrl": "", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "secret": "ThisIsAnExampleKeyForDevPurposeOnly", + "redirectUris": [ + "http://localhost:8920/*", + "http://localhost:8921/*", + "http://localhost:8922/*", + "http://localhost:8923/*" + ], + "webOrigins": [ + "http://localhost:8920", + "http://localhost:8921", + "http://localhost:8922", + "http://localhost:8923" + ], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": true, + "protocol": "openid-connect", + "attributes": { + "access.token.lifespan": "-1", + "client.secret.creation.time": "1707820779", + "user.info.response.signature.alg": "RS256", + "post.logout.redirect.uris": "http://localhost:8920/*##http://localhost:8921/*", + "oauth2.device.authorization.grant.enabled": "false", + "use.jwks.url": "false", + "backchannel.logout.revoke.offline.tokens": "false", + "use.refresh.tokens": "true", + "tls-client-certificate-bound-access-tokens": "false", + "oidc.ciba.grant.enabled": "false", + "backchannel.logout.session.required": "true", + "client_credentials.use_refresh_token": "false", + "acr.loa.map": "{}", + "require.pushed.authorization.requests": "false", + "display.on.consent.screen": "false", + "client.session.idle.timeout": "-1", + "token.response.type.bearer.lower-case": "false" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "0d004a05-7049-452c-83a8-2bae2b5d8015", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + }, + { + "id": "2a4e007a-2fc4-4f43-aace-b93aec9221b4", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "rootUrl": "${authAdminUrl}", + "baseUrl": "/admin/calendars/console/", + "surrogateAuthRequired": false, + "enabled": true, + "alwaysDisplayInConsole": false, + "clientAuthenticatorType": "client-secret", + "redirectUris": ["/admin/calendars/console/*"], + "webOrigins": ["+"], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": { + "post.logout.redirect.uris": "+", + "pkce.code.challenge.method": "S256" + }, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "4913be96-5827-46a4-9909-562c2dd5bef6", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "acr", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access", + "microprofile-jwt" + ] + } + ], + "clientScopes": [ + { + "id": "74aeb8e2-a1b6-4897-9eaf-d922becea170", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "994b8f5e-dfc1-4154-a936-347336e6422a", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "d853f97e-80f8-470e-8447-815b289d9ae3", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "26a9f3ef-cff0-4dee-9fe9-778cd1d2a771", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "af52ccc3-4ecb-49b4-9a67-5d4172f16070", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "efb82630-8835-4de0-944e-ac5ea51eca48", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "2256189a-7970-4244-b496-64cbba3ce582", + "name": "acr", + "description": "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "6d7f8b9e-997e-40f8-bae5-83d2647fbeff", + "name": "acr loa level", + "protocol": "openid-connect", + "protocolMapper": "oidc-acr-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + } + ] + }, + { + "id": "b83cebb6-f086-48e2-8e5a-9802736342f2", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "b99113c6-ccfb-43d4-acd1-09dd34cdf5bc", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "696211d7-c434-495f-b3a0-a1b88bebfd6e", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "16845bd9-5626-4484-b4c5-00af52d8ad8b", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "5828a7d9-cdc7-456b-a747-16bf83c2f57d", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "ce289e05-eca4-4323-b457-822d39cc6d49", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "abe63488-9a39-4e29-a0a8-824db0887b60", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "15690cfb-e14c-46e8-8494-22a0365a4b0c", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "03cf0e4c-c2a5-4203-88c4-5391d361ba15", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "23b1a1da-2ecc-4db7-8d33-4e9233a81e89", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "long" + } + }, + { + "id": "26a72777-56eb-4b46-acca-eca8168e29fc", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "4ae1896b-ea82-4604-8f0e-72133fdee05c", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "79712bcf-b7f7-4ca3-b97c-418f48fded9b", + "name": "first name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "first_name", + "jsonType.label": "String" + } + }, + { + "id": "6397c5e9-95ea-4c31-bd44-a8acf1d18472", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "7f741e96-41fe-4021-bbfd-506e7eb94e69", + "name": "last name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "last_name", + "jsonType.label": "String" + } + }, + { + "id": "5ca62964-2d04-4e8e-963d-e3b08cf32d7c", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "954a5dff-cc19-4dde-b996-787f767db4cc", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "1eba19bf-6fa1-4608-ad2d-d4346580c93d", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "e7bdd267-fcce-451f-b3e1-a775cf611dd2", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "a9a8918c-af00-48a5-a8b3-a28a83653f71", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "cd725067-b6ba-42f1-a940-97a16a23cb85", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "a4e1812c-4093-4666-a6b3-03c5d9b5ca9f", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + }, + { + "id": "d6690292-74d1-48ac-855d-2f0f3799829e", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "userinfo.token.claim": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "ce8f1215-0462-4e87-8a3b-18488aee0267", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "0ce95430-80aa-4dd6-994b-5a67302ba531", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "8da0d3b1-d609-417e-9adc-1de77549baf9", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "f89a9158-7c03-49b0-8a3c-d0b75e2ce1b4", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "fb109597-e31e-46d7-84c5-62e5fcf32ac8", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "qb109597-e31e-46d7-7844-62e5fcf32ac8", + "name": "email sub", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "sub", + "jsonType.label": "String" + } + }, + { + "id": "61c135e5-2447-494b-bc70-9612f383be27", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins", + "acr" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": ["jboss-logging"], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "74dffa9a-5d4f-4ce3-9708-885212f56861", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "48096073-ceae-4e68-a15b-f1aa390dcce5", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "51b0e87c-ee04-4664-a299-f8e49cb7a9ac", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": ["200"] + } + }, + { + "id": "6379b091-2289-4fe7-894c-c03f1bd0e69b", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": ["true"] + } + }, + { + "id": "97ae8320-a439-463b-817e-05bd4a6c39d1", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-full-name-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper" + ] + } + }, + { + "id": "49131ffc-4831-4e3e-a466-f9f08aa1bee0", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "e12647d2-e21f-49bc-a8c6-28154c5544d2", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "saml-user-attribute-mapper", + "oidc-address-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "oidc-full-name-mapper", + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "c9f00ef2-00d9-44bd-9b6c-3b3bf57e44ba", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": ["true"], + "client-uris-must-match": ["true"] + } + } + ], + "org.keycloak.userprofile.UserProfileProvider": [ + { + "id": "96260850-72a5-4b49-b96b-5a33d0b5337d", + "providerId": "declarative-user-profile", + "subComponents": {}, + "config": {} + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "55d93b4d-fe05-46a1-a832-36f380aaddf7", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": ["100"] + } + }, + { + "id": "bee288b4-ecdf-4ec4-8c31-ee330f1e8f95", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": ["100"], + "algorithm": ["HS256"] + } + }, + { + "id": "2aa8f54d-8b4b-4eb7-a05b-89211f544358", + "name": "rsa-enc-generated", + "providerId": "rsa-enc-generated", + "subComponents": {}, + "config": { + "priority": ["100"], + "algorithm": ["RSA-OAEP"] + } + }, + { + "id": "23ad48f4-2275-4a0d-aa0d-1e0691f9c620", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": ["100"] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "0c349304-21fd-47ff-8dc6-46efb107b7e9", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false + } + ] + }, + { + "id": "cf1ed416-7274-4804-88bf-4261b0bacdc6", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "d949f1f1-4622-49ec-b74a-4b8a58c653d2", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "3deb6d9d-2064-410c-af99-b1601cd9b1c4", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "f777c4be-f7d1-453e-a9d7-a2a235b7975b", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "1bc12f49-e2ef-42bd-959a-0983e1cd4d65", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Account verification options", + "userSetupAllowed": false + } + ] + }, + { + "id": "324cdcf5-8f31-4768-9db9-63208f182b39", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "23d17138-8ebd-4195-91d3-614094f62070", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false + } + ] + }, + { + "id": "61fec72a-bfd2-42e8-95c1-fa0b76c1cd2b", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "dc00b9a8-fc37-4591-a1ea-07c7f884d394", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "forms", + "userSetupAllowed": false + } + ] + }, + { + "id": "4f27245a-49b8-4870-a5e2-f0ea624a792c", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "5b2c66e1-7bbf-4707-9db8-244269b68164", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "autheticatorFlow": true, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "4bcddec4-4260-4f4f-a757-3aff9b1d30f3", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "04a94e38-b7fb-48f6-8d63-5640f835c619", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "User creation or linking", + "userSetupAllowed": false + } + ] + }, + { + "id": "bfcf5112-96ac-485a-8663-b02ad41af919", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "e262d10d-ad0d-4d18-bc05-3a44f7d21736", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": true, + "flowAlias": "Authentication Options", + "userSetupAllowed": false + } + ] + }, + { + "id": "b671c4b3-22b6-4aac-a1d1-464a2101767c", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": true, + "flowAlias": "registration form", + "userSetupAllowed": false + } + ] + }, + { + "id": "f570e064-0e62-4eae-8087-8b06751b8f33", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + }, + { + "id": "07124099-1d10-4148-ac06-4b0b700908da", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "autheticatorFlow": false, + "userSetupAllowed": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "autheticatorFlow": true, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false + } + ] + }, + { + "id": "0a5fa089-f987-4903-9170-36565edda152", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "autheticatorFlow": false, + "userSetupAllowed": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "d2818365-2189-4003-9817-0ad5368e37f3", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "72508559-0176-4eee-a77e-0795d652be12", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "CONFIGURE_RECOVERY_AUTHN_CODES", + "name": "Recovery Authentication Codes", + "providerId": "CONFIGURE_RECOVERY_AUTHN_CODES", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "UPDATE_EMAIL", + "name": "Update Email", + "providerId": "UPDATE_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register", + "name": "Webauthn Register", + "providerId": "webauthn-register", + "enabled": true, + "defaultAction": false, + "priority": 70, + "config": {} + }, + { + "alias": "webauthn-register-passwordless", + "name": "Webauthn Register Passwordless", + "providerId": "webauthn-register-passwordless", + "enabled": true, + "defaultAction": false, + "priority": 80, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "clientOfflineSessionMaxLifespan": "0", + "clientSessionIdleTimeout": "0", + "parRequestUriLifespan": "60", + "clientSessionMaxLifespan": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5", + "realmReusableOtpCode": "false" + }, + "keycloakVersion": "20.0.1", + "userManagedAccessAllowed": false, + "clientProfiles": { + "profiles": [] + }, + "clientPolicies": { + "policies": [] + } + } +] diff --git a/docker/davical/Dockerfile b/docker/davical/Dockerfile new file mode 100644 index 0000000..11c91a0 --- /dev/null +++ b/docker/davical/Dockerfile @@ -0,0 +1,39 @@ +# DAViCal CalDAV Server +# Based on Debian with Apache and PHP +FROM debian:bookworm-slim + +ENV DEBIAN_FRONTEND=noninteractive + +# Install dependencies +RUN apt-get update && apt-get install -y \ + apache2 \ + libapache2-mod-php \ + php-pgsql \ + php-xml \ + php-curl \ + php-imap \ + php-ldap \ + davical \ + postgresql-client \ + && rm -rf /var/lib/apt/lists/* + +# Enable required Apache modules +RUN a2enmod rewrite + +# Copy Apache configuration +COPY davical.conf /etc/apache2/sites-available/davical.conf +RUN a2dissite 000-default && a2ensite davical + +# Copy DAViCal configuration +COPY config.php /etc/davical/config.php + +# Copy and setup entrypoint +COPY entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +# Set permissions +RUN chown -R www-data:www-data /var/log/apache2 + +EXPOSE 80 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/docker/davical/config.php b/docker/davical/config.php new file mode 100644 index 0000000..a5f646f --- /dev/null +++ b/docker/davical/config.php @@ -0,0 +1,64 @@ +pg_connect[] = 'host=' . getenv('PGHOST') . ' port=' . (getenv('PGPORT') ?: '5432') . ' dbname=' . getenv('PGDATABASE') . ' user=' . getenv('PGUSER') . ' password=' . getenv('PGPASSWORD'); + +// System name +$c->system_name = 'Calendars DAViCal Server'; + +// Admin email +$c->admin_email = 'admin@example.com'; + +// Allow public access for CalDAV discovery +$c->public_freebusy_url = true; + +// Default locale +$c->default_locale = 'en_US.UTF-8'; + +// Logging - enable for debugging authentication issues +$c->log_caldav_queries = true; + +// Trust proxy headers for auth +$c->trust_x_forwarded = true; + +// Configure base path when behind reverse proxy +// Override SCRIPT_NAME so DAViCal generates correct URLs +// DAViCal uses $_SERVER['SCRIPT_NAME'] to determine the base path for URLs +// We set it to the proxy path WITHOUT /caldav.php since DAViCal will add that itself +if (isset($_SERVER['HTTP_X_FORWARDED_PREFIX'])) { + $_SERVER['SCRIPT_NAME'] = rtrim($_SERVER['HTTP_X_FORWARDED_PREFIX'], '/'); +} elseif (isset($_SERVER['HTTP_X_SCRIPT_NAME'])) { + $_SERVER['SCRIPT_NAME'] = rtrim($_SERVER['HTTP_X_SCRIPT_NAME'], '/'); +} + +// Custom authentication function to use X-Forwarded-User header +// This function is called by DAViCal's authentication system +function authenticate_via_forwarded_user( $username, $password ) { + // Check if X-Forwarded-User header is present + if (isset($_SERVER['HTTP_X_FORWARDED_USER'])) { + $forwarded_user = trim($_SERVER['HTTP_X_FORWARDED_USER']); + + // If the username from Basic Auth matches X-Forwarded-User, authenticate + // Users with password '*' are externally authenticated + if (strtolower($username) === strtolower($forwarded_user)) { + // Return the username to authenticate as this user + // DAViCal will check if user exists and has password '*' + return $forwarded_user; + } + } + + // Fall back to standard authentication + return false; +} + +// Use custom authentication hook +$c->authenticate_hook = array( + 'call' => 'authenticate_via_forwarded_user', + 'config' => array() +); diff --git a/docker/davical/davical.conf b/docker/davical/davical.conf new file mode 100644 index 0000000..fab6fe8 --- /dev/null +++ b/docker/davical/davical.conf @@ -0,0 +1,22 @@ + + ServerName localhost + DocumentRoot /usr/share/davical/htdocs + DirectoryIndex index.php + + Alias /images/ /usr/share/davical/htdocs/images/ + + + AllowOverride All + Require all granted + + + AcceptPathInfo On + + # CalDAV principal URL + RewriteEngine On + RewriteRule ^/caldav/(.*)$ /caldav.php/$1 [L] + RewriteRule ^/\.well-known/caldav /caldav.php [R=301,L] + + ErrorLog ${APACHE_LOG_DIR}/davical_error.log + CustomLog ${APACHE_LOG_DIR}/davical_access.log combined + diff --git a/docker/davical/run-migrations b/docker/davical/run-migrations new file mode 100755 index 0000000..8caef0f --- /dev/null +++ b/docker/davical/run-migrations @@ -0,0 +1,93 @@ +#!/bin/bash +### +# Run DB migrations necessary to use Davical. +# Will create the database on first-run, and only run necessary migrations on subsequent runs. +# +# Requires the following environment variables in addition to the container variables. +# - ROOT_PGUSER +# - ROOT_PGPASSWORD +# - DAVICAL_ADMIN_PASS +### + +set -e + +if [ -z ${ROOT_PGUSER+x} ]; then + echo "ROOT_PGUSER must be set" + exit 1 +fi +if [ -z ${ROOT_PGPASSWORD+x} ]; then + echo "ROOT_PGPASSWORD must be set" + exit 1 +fi +if [ -z ${DAVICAL_ADMIN_PASS+x} ]; then + echo "DAVICAL_ADMIN_PASS must be set" + exit 1 +fi + +if [ -z ${DBA_PGPASSWORD+x} ]; then + DBA_PGPASSWORD=$PGPASSWORD +fi + +if [ -z ${DAVICAL_SCHEMA+x} ]; then + DAVICAL_SCHEMA=$DBA_PGUSER +fi + +# store PG environment so it can be overridden as-needed +DAVICAL_PGUSER=$PGUSER +DAVICAL_PGPASSWORD=$PGPASSWORD +DAVICAL_PGDATABASE=$PGDATABASE + +run_migrations() { + echo "Running dba/update-davical-database, which should automatically apply any necessary DB migrations." + /usr/share/davical/dba/update-davical-database \ + --dbname $DAVICAL_PGDATABASE \ + --dbuser $DBA_PGUSER \ + --dbhost $PGHOST \ + --dbpass $DBA_PGPASSWORD \ + --appuser $DAVICAL_PGUSER \ + --owner $DBA_PGUSER +} + +export PGUSER=$ROOT_PGUSER +export PGPASSWORD=$ROOT_PGPASSWORD +export PGDATABASE= + +# Wait for PG connection +retries=10 +until pg_isready -q -t 3; do + [[ retries -eq 0 ]] && echo "Could not connect to Postgres" && exit 1 + echo "Waiting for Postgres to be available" + retries=$((retries-1)) + sleep 1 +done + +# Check whether the database has already been setup, with awl tables. +tables=$(psql -d $DAVICAL_PGDATABASE -c "\\dt") +if echo "$tables" | grep -q "awl_db_revision"; then + # The database already exists - just run any outstanding migrations + run_migrations + exit 0 +fi + +echo "Database has not been created - running first-time database setup" + +# the rest of the commands are run as the dba superuser +export PGUSER=$DBA_PGUSER +export PGPASSWORD=$DBA_PGPASSWORD +export PGDATABASE=$DAVICAL_PGDATABASE + +psql -qXAt -f /usr/share/awl/dba/awl-tables.sql +psql -qXAt -f /usr/share/awl/dba/schema-management.sql +psql -qXAt -f /usr/share/davical/dba/davical.sql +run_migrations +psql -qXAt -f /usr/share/davical/dba/base-data.sql + +# DAViCal only uses salted SHA1 at-best, but it's better than storing the password in plaintext! +# see https://wiki.davical.org/index.php?title=Force_Admin_Password +# from https://gitlab.com/davical-project/awl/-/blob/3f044e2dc8435c2eeba61a3c41ec11c820711ab3/inc/DataUpdate.php#L48-58 +salted_password=$(php -r 'require "/usr/share/awl/inc/AWLUtilities.php"; echo session_salted_sha1($argv[1]);' "$DAVICAL_ADMIN_PASS") +psql -qX \ + -v pw="'$salted_password'" \ + <() " +""" +from __future__ import unicode_literals + +import re + +import requests + +from gitlint.rules import CommitMessageTitle, LineRule, RuleViolation + + +class GitmojiTitle(LineRule): + """ + This rule will enforce that each commit title is of the form "() " + where gitmoji is an emoji from the list defined in https://gitmoji.carloscuesta.me and + subject should be all lowercase + """ + + id = "UC1" + name = "title-should-have-gitmoji-and-scope" + target = CommitMessageTitle + + def validate(self, title, _commit): + """ + Download the list possible gitmojis from the project's github repository and check that + title contains one of them. + """ + gitmojis = requests.get( + "https://raw.githubusercontent.com/carloscuesta/gitmoji/master/packages/gitmojis/src/gitmojis.json" + ).json()["gitmojis"] + emojis = [item["emoji"] for item in gitmojis] + pattern = r"^({:s})\(.*\)\s[a-zA-Z].*$".format("|".join(emojis)) + if not re.search(pattern, title): + violation_msg = 'Title does not match regex "() "' + return [RuleViolation(self.id, violation_msg, title)] diff --git a/renovate.json b/renovate.json new file mode 100644 index 0000000..edf8b11 --- /dev/null +++ b/renovate.json @@ -0,0 +1,25 @@ +{ + "extends": ["github>numerique-gouv/renovate-configuration"], + "dependencyDashboard": true, + "labels": ["dependencies", "noChangeLog"], + "packageRules": [ + { + "groupName": "allowed redis versions", + "matchManagers": ["pep621"], + "matchPackageNames": ["redis"], + "allowedVersions": "<6.0.0" + }, + { + "groupName": "allowed pylint versions", + "matchManagers": ["pep621"], + "matchPackageNames": ["pylint"], + "allowedVersions": "<4.0.0" + }, + { + "description": "Disable requires-python updates - managed manually", + "matchManagers": ["pep621"], + "matchPackageNames": ["python"], + "enabled": false + } + ] +} \ No newline at end of file diff --git a/src/backend/.dockerignore b/src/backend/.dockerignore new file mode 100644 index 0000000..e4b67e7 --- /dev/null +++ b/src/backend/.dockerignore @@ -0,0 +1,33 @@ +# Python +__pycache__ +*.pyc +**/__pycache__ +**/*.pyc +venv +.venv + +# System-specific files +.DS_Store +**/.DS_Store + +# Docker +compose.* +env.d + +# Docs +docs +*.md +*.log + +# Development/test cache & configurations +data +.cache +.circleci +.git +.vscode +.iml +.idea +db.sqlite3 +.mypy_cache +.pylint.d +.pytest_cache diff --git a/src/backend/.pylintrc b/src/backend/.pylintrc new file mode 100644 index 0000000..1aeec30 --- /dev/null +++ b/src/backend/.pylintrc @@ -0,0 +1,472 @@ +[MASTER] + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=migrations + +# Add files or directories matching the regex patterns to the blacklist. The +# regex matches against base names, not paths. +ignore-patterns= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the +# number of processors available to use. +jobs=0 + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins=pylint_django,pylint.extensions.no_self_use + +# Pickle collected data for later comparisons. +persistent=yes + +# Specify a configuration file. +#rcfile= + +# When enabled, pylint would attempt to guess common misconfiguration and emit +# user-friendly hints instead of false-positive error messages +suggestion-mode=yes + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + + +[MESSAGES CONTROL] + +# Only show warnings with the listed confidence levels. Leave empty to show +# all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED +confidence= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +disable=bad-inline-option, + deprecated-pragma, + django-not-configured, + file-ignored, + locally-disabled, + no-self-use, + raw-checker-failed, + suppressed-message, + useless-suppression + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time (only on the command line, not in the configuration file where +# it should appear only once). See also the "--disable" option for examples. +enable=c-extension-no-member + + +[REPORTS] + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + +# Set the output format. Available formats are text, parseable, colorized, json +# and msvs (visual studio).You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=text + +# Tells whether to display a full report or only the messages +reports=no + +# Activate the evaluation score. +score=yes + + +[REFACTORING] + +# Maximum number of nested blocks for function / method body +max-nested-blocks=5 + +# Complete name of functions that never returns. When checking for +# inconsistent-return-statements if a never returning function is called then +# it will be considered as an explicit return statement and no message will be +# printed. +never-returning-functions=optparse.Values,sys.exit + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[SPELLING] + +# Limits count of emitted suggestions for spelling mistakes +max-spelling-suggestions=4 + +# Spelling dictionary name. Available dictionaries: none. To make it working +# install python-enchant package. +spelling-dict= + +# List of comma separated words that should not be checked. +spelling-ignore-words= + +# A path to a file that contains private dictionary; one word per line. +spelling-private-dict-file= + +# Tells whether to store unknown words to indicated private dictionary in +# --spelling-private-dict-file option instead of raising a message. +spelling-store-unknown-words=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME, + XXX, + TODO + + +[TYPECHECK] + +# List of decorators that produce context managers, such as +# contextlib.contextmanager. Add to this list to register other decorators that +# produce valid context managers. +contextmanager-decorators=contextlib.contextmanager + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E1101 when accessed. Python regular +# expressions are accepted. +generated-members= + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# This flag controls whether pylint should warn about no-member and similar +# checks whenever an opaque object is returned when inferring. The inference +# can return multiple potential results while evaluating a Python object, but +# some branches might not be evaluated, which results in partial inference. In +# that case, it might be useful to still emit no-member and other checks for +# the rest of the inferred objects. +ignore-on-opaque-inference=yes + +# List of class names for which member attributes should not be checked (useful +# for classes with dynamically set attributes). This supports the use of +# qualified names. +ignored-classes=optparse.Values,thread._local,_thread._local,responses, + Template,Contact + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis. It +# supports qualified module names, as well as Unix pattern matching. +ignored-modules= + +# Show a hint with possible names when a member name was not found. The aspect +# of finding the hint is based on edit distance. +missing-member-hint=yes + +# The minimum edit distance a name should have in order to be considered a +# similar match for a missing member name. +missing-member-hint-distance=1 + +# The total number of similar names that should be taken in consideration when +# showing a hint for a missing member. +missing-member-max-choices=1 + + +[VARIABLES] + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + +# Tells whether unused global variables should be treated as a violation. +allow-global-unused-variables=yes + +# List of strings which can identify a callback function by name. A callback +# name must start or end with one of those strings. +callbacks=cb_, + _cb + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_ + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.*|^ignored_|^unused_ + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# List of qualified module names which can have objects that can redefine +# builtins. +redefining-builtins-modules=six.moves,past.builtins,future.builtins + + +[FORMAT] + +# Expected format of line ending, e.g. empty (any line ending), LF or CRLF. +expected-line-ending-format= + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(#\s*)??$ + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Maximum number of characters on a single line. +max-line-length=100 + +# Maximum number of lines in a module +max-module-lines=1000 + +# Allow the body of a class to be on the same line as the declaration if body +# contains single statement. +single-line-class-stmt=no + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + + +[SIMILARITIES] + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=yes + +# Minimum lines number of a similarity. +# First implementations of CMS wizards have common fields we do not want to factorize for now +min-similarity-lines=35 + + +[BASIC] + +# Naming style matching correct argument names +argument-naming-style=snake_case + +# Regular expression matching correct argument names. Overrides argument- +# naming-style +#argument-rgx= + +# Naming style matching correct attribute names +attr-naming-style=snake_case + +# Regular expression matching correct attribute names. Overrides attr-naming- +# style +#attr-rgx= + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo, + bar, + baz, + toto, + tutu, + tata + +# Naming style matching correct class attribute names +class-attribute-naming-style=any + +# Regular expression matching correct class attribute names. Overrides class- +# attribute-naming-style +#class-attribute-rgx= + +# Naming style matching correct class names +class-naming-style=PascalCase + +# Regular expression matching correct class names. Overrides class-naming-style +#class-rgx= + +# Naming style matching correct constant names +const-naming-style=UPPER_CASE + +# Regular expression matching correct constant names. Overrides const-naming- +# style +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__)|urlpatterns|logger)$ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + +# Naming style matching correct function names +function-naming-style=snake_case + +# Regular expression matching correct function names. Overrides function- +# naming-style +#function-rgx= + +# Good variable names which should always be accepted, separated by a comma +good-names=i, + j, + k, + cm, + ex, + Run, + _ + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Naming style matching correct inline iteration names +inlinevar-naming-style=any + +# Regular expression matching correct inline iteration names. Overrides +# inlinevar-naming-style +#inlinevar-rgx= + +# Naming style matching correct method names +method-naming-style=snake_case + +# Regular expression matching correct method names. Overrides method-naming- +# style +method-rgx=([a-z_][a-z0-9_]{2,50}|setUp|set[Uu]pClass|tearDown|tear[Dd]ownClass|assert[A-Z]\w*|maxDiff|test_[a-z0-9_]+)$ + +# Naming style matching correct module names +module-naming-style=snake_case + +# Regular expression matching correct module names. Overrides module-naming- +# style +#module-rgx= + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=^_ + +# List of decorators that produce properties, such as abc.abstractproperty. Add +# to this list to register other decorators that produce valid properties. +property-classes=abc.abstractproperty + +# Naming style matching correct variable names +variable-naming-style=snake_case + +# Regular expression matching correct variable names. Overrides variable- +# naming-style +#variable-rgx= + + +[IMPORTS] + +# Allow wildcard imports from modules that define __all__. +allow-wildcard-with-all=no + +# Analyse import fallback blocks. This can be used to support both Python 2 and +# 3 compatible code, which means that the block might have code that exists +# only in one or another interpreter, leading to false positives when analysed. +analyse-fallback-blocks=no + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=optparse,tkinter.tix + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + +# Force import order to recognize a module as part of the standard +# compatibility libraries. +known-standard-library= + +# Force import order to recognize a module as part of a third party library. +known-third-party=enchant + + +[CLASSES] + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__, + __new__, + setUp + +# List of member names, which should be excluded from the protected access +# warning. +exclude-protected=_asdict, + _fields, + _replace, + _source, + _make + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Maximum number of boolean expressions in a if statement +max-bool-expr=5 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of locals for function / method body +max-locals=20 + +# Maximum number of parents for a class (see R0901). +max-parents=10 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of statements in function / method body +max-statements=50 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=0 + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=builtins.Exception diff --git a/src/backend/Dockerfile b/src/backend/Dockerfile new file mode 100644 index 0000000..059c691 --- /dev/null +++ b/src/backend/Dockerfile @@ -0,0 +1,158 @@ +# Django calendars + +# ---- base image to inherit from ---- +FROM python:3.13.9-alpine AS base + +# Upgrade pip to its latest release to speed up dependencies installation +# We must do taht to avoid having an outdated pip version with security issues +RUN python -m pip install --upgrade pip setuptools + +# Upgrade system packages to install security updates +RUN apk update && \ + apk upgrade && \ + apk add git + +# ---- Back-end builder image ---- +FROM base AS back-builder + +ENV UV_COMPILE_BYTECODE=1 +ENV UV_LINK_MODE=copy + +# Disable Python downloads, because we want to use the system interpreter +# across both images. If using a managed Python version, it needs to be +# copied from the build image into the final image; +ENV UV_PYTHON_DOWNLOADS=0 + +# install uv +COPY --from=ghcr.io/astral-sh/uv:0.9.10 /uv /uvx /bin/ + +WORKDIR /app + + +RUN --mount=type=cache,target=/root/.cache/uv \ + --mount=type=bind,source=uv.lock,target=uv.lock \ + --mount=type=bind,source=pyproject.toml,target=pyproject.toml \ + uv sync --locked --no-install-project --no-dev +COPY . /app +RUN --mount=type=cache,target=/root/.cache/uv \ + uv sync --locked --no-dev + +# ---- static link collector ---- +FROM base AS link-collector +ARG CALENDARS_STATIC_ROOT=/data/static + +# Install pango & rdfind +RUN apk add \ + pango \ + rdfind + +WORKDIR /app + +# Copy the application from the builder +COPY --from=back-builder /app /app + +ENV PATH="/app/.venv/bin:$PATH" + + +# collectstatic +RUN DJANGO_CONFIGURATION=Build \ + python manage.py collectstatic --noinput + +# Replace duplicated file by a symlink to decrease the overall size of the +# final image +RUN rdfind -makesymlinks true -followsymlinks true -makeresultsfile false ${CALENDARS_STATIC_ROOT} + +# ---- Core application image ---- +FROM base AS core + +ENV PYTHONUNBUFFERED=1 + +# Install required system libs +RUN apk add \ + cairo \ + file \ + font-noto \ + font-noto-emoji \ + gettext \ + gdk-pixbuf \ + libffi-dev \ + pandoc \ + pango \ + shared-mime-info + +RUN wget https://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types -O /etc/mime.types + +# Give the "root" group the same permissions as the "root" user on /etc/passwd +# to allow a user belonging to the root group to add new users; typically the +# docker user (see entrypoint). +RUN chmod g=u /etc/passwd + +# Copy the application from the builder +COPY --from=back-builder /app /app + +WORKDIR /app + +ENV PATH="/app/.venv/bin:$PATH" + +# Generate compiled translation messages +RUN DJANGO_CONFIGURATION=Build \ + python manage.py compilemessages --ignore=".venv/**/*" + + +# We wrap commands run in this container by the following entrypoint that +# creates a user on-the-fly with the container user ID (see USER) and root group +# ID. +ENTRYPOINT [ "/app/entrypoint" ] + +# ---- Development image ---- +FROM core AS backend-development + +# Switch back to the root user to install development dependencies +USER root:root + +# Install psql +RUN apk add postgresql-client + +# Install uv for development dependencies +COPY --from=ghcr.io/astral-sh/uv:0.9.10 /uv /uvx /bin/ + +# Install development dependencies (ensure venv is created and used) +RUN uv sync --all-extras --locked + +# Ensure venv is accessible and PATH is set +ENV PATH="/app/.venv/bin:$PATH" +ENV VIRTUAL_ENV="/app/.venv" + +# Restore the un-privileged user running the application +ARG DOCKER_USER +USER ${DOCKER_USER} + +# Target database host (e.g. database engine following docker compose services +# name) & port +ENV DB_HOST=postgresql \ + DB_PORT=5432 + +# Run django development server +CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"] + +# ---- Production image ---- +FROM core AS backend-production + +ARG CALENDARS_STATIC_ROOT=/data/static + +# Remove git, we don't need it in the production image +RUN apk del git + +# Gunicorn +RUN mkdir -p /usr/local/etc/gunicorn +COPY docker/files/usr/local/etc/gunicorn/calendars.py /usr/local/etc/gunicorn/calendars.py + +# Un-privileged user running the application +ARG DOCKER_USER +USER ${DOCKER_USER} + +# Copy statics +COPY --from=link-collector ${CALENDARS_STATIC_ROOT} ${CALENDARS_STATIC_ROOT} + +# The default command runs gunicorn WSGI server in calendars' main module +CMD ["gunicorn", "-c", "/app/gunicorn.conf.py", "calendars.wsgi:application"] diff --git a/src/backend/MANIFEST.in b/src/backend/MANIFEST.in new file mode 100644 index 0000000..4a8db10 --- /dev/null +++ b/src/backend/MANIFEST.in @@ -0,0 +1,3 @@ +include LICENSE +include README.md +recursive-include src/backend/calendars *.html *.png *.gif *.css *.ico *.jpg *.jpeg *.po *.mo *.eot *.svg *.ttf *.woff *.woff2 diff --git a/src/backend/__init__.py b/src/backend/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/calendars/__init__.py b/src/backend/calendars/__init__.py new file mode 100644 index 0000000..9cca34c --- /dev/null +++ b/src/backend/calendars/__init__.py @@ -0,0 +1,5 @@ +"""Calendars package. Import the celery app early to load shared task form dependencies.""" + +from .celery_app import app as celery_app + +__all__ = ["celery_app"] diff --git a/src/backend/calendars/celery_app.py b/src/backend/calendars/celery_app.py new file mode 100644 index 0000000..7b0f82b --- /dev/null +++ b/src/backend/calendars/celery_app.py @@ -0,0 +1,26 @@ +"""Calendars celery configuration file.""" + +import os + +from celery import Celery +from configurations.importer import install + +# Set the default Django settings module for the 'celery' program. +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calendars.settings") +os.environ.setdefault("DJANGO_CONFIGURATION", "Development") + +install(check_options=True) + +# Can be loaded only after install call. +from django.conf import settings # pylint: disable=wrong-import-position + +app = Celery("calendars") + +# Using a string here means the worker doesn't have to serialize +# the configuration object to child processes. +# - namespace='CELERY' means all celery-related configuration keys +# should have a `CELERY_` prefix. +app.config_from_object("django.conf:settings", namespace="CELERY") + +# Load task modules from all registered Django apps. +app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) diff --git a/src/backend/calendars/configuration/theme/default.json b/src/backend/calendars/configuration/theme/default.json new file mode 100644 index 0000000..1c5165f --- /dev/null +++ b/src/backend/calendars/configuration/theme/default.json @@ -0,0 +1,69 @@ +{ + "footer": { + "default": { + "externalLinks": [ + { + "label": "Github", + "href": "https://github.com/suitenumerique/calendars/" + }, + { + "label": "ANCT", + "href": "https://anct.gouv.fr/" + } + ], + "license": { + "label": "Unless otherwise stated, all content on this site is under", + "link": { + "label": "licence etalab-2.0", + "href": "https://github.com/etalab/licence-ouverte/blob/master/LO.md" + } + } + }, + "en": { + "legalLinks": [ + { + "label": "Legal Notice", + "href": "#" + }, + { + "label": "Personal data and cookies", + "href": "#" + }, + { + "label": "Accessibility: non compliant", + "href": "#" + } + ], + "license": { + "label": "Unless otherwise stated, all content on this site is under", + "link": { + "label": "licence etalab-2.0", + "href": "https://github.com/etalab/licence-ouverte/blob/master/LO.md" + } + } + }, + "fr": { + "legalLinks": [ + { + "label": "Mentions légales", + "href": "#" + }, + { + "label": "Données personnelles et cookies", + "href": "#" + }, + { + "label": "Accessibilité: non conforme", + "href": "#" + } + ], + "license": { + "label": "Sauf mention contraire, tout le contenu de ce site est sous", + "link": { + "label": "licence etalab-2.0", + "href": "https://github.com/etalab/licence-ouverte/blob/master/LO.md" + } + } + } + } +} diff --git a/src/backend/calendars/settings.py b/src/backend/calendars/settings.py new file mode 100755 index 0000000..a489afe --- /dev/null +++ b/src/backend/calendars/settings.py @@ -0,0 +1,919 @@ +""" +Django settings for calendar project. + +Generated by 'django-admin startproject' using Django 3.1.5. + +For more information on this file, see +https://docs.djangoproject.com/en/3.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/3.1/ref/settings/ +""" + +import os +import tomllib +from socket import gethostbyname, gethostname + +from django.utils.translation import gettext_lazy as _ + +import dj_database_url +import sentry_sdk +from configurations import Configuration, values +from lasuite.configuration.values import SecretFileValue +from sentry_sdk.integrations.django import DjangoIntegration + +# pylint: disable=too-many-lines + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +DATA_DIR = os.environ.get("DATA_DIR", os.path.join("/", "data")) + + +def get_release(): + """ + Get the current release of the application + """ + try: + with open(os.path.join(BASE_DIR, "pyproject.toml"), "rb") as f: + pyproject_data = tomllib.load(f) + return pyproject_data["project"]["version"] + except (FileNotFoundError, KeyError): + return "NA" # Default: not available + + +class Base(Configuration): + """ + This is the base configuration every configuration (aka environment) should inherit from. It + is recommended to configure third-party applications by creating a configuration mixins in + ./configurations and compose the Base configuration with those mixins. + + It depends on an environment variable that SHOULD be defined: + + * DJANGO_SECRET_KEY + + You may also want to override default configuration by setting the following environment + variables: + + * SENTRY_DSN + * DB_NAME + * DB_HOST + * DB_PASSWORD + * DB_USER + """ + + DEBUG = False + LOAD_E2E_URLS = False + USE_SWAGGER = False + + API_VERSION = "v1.0" + + # DAViCal CalDAV server URL + DAVICAL_URL = values.Value( + "http://davical:80", environ_name="DAVICAL_URL", environ_prefix=None + ) + + # Security + ALLOWED_HOSTS = values.ListValue([]) + SECRET_KEY = SecretFileValue(None) + SERVER_TO_SERVER_API_TOKENS = values.ListValue([]) + + # Application definition + ROOT_URLCONF = "calendars.urls" + WSGI_APPLICATION = "calendars.wsgi.application" + + # Database + DATABASES = { + "default": dj_database_url.config() + if os.environ.get("DATABASE_URL") + else { + "ENGINE": values.Value( + "django.db.backends.postgresql", + environ_name="DB_ENGINE", + environ_prefix=None, + ), + "NAME": values.Value( + "calendars", environ_name="DB_NAME", environ_prefix=None + ), + "USER": values.Value("pgroot", environ_name="DB_USER", environ_prefix=None), + "PASSWORD": SecretFileValue( + "pass", environ_name="DB_PASSWORD", environ_prefix=None + ), + "HOST": values.Value( + "localhost", environ_name="DB_HOST", environ_prefix=None + ), + "PORT": values.Value(5432, environ_name="DB_PORT", environ_prefix=None), + } + } + DEFAULT_AUTO_FIELD = "django.db.models.AutoField" + + # Static files (CSS, JavaScript, Images) + STATIC_URL = "/static/" + STATIC_ROOT = os.path.join(DATA_DIR, "static") + MEDIA_URL = "/media/" + MEDIA_URL_PREVIEW = "/media/preview/" + MEDIA_ROOT = os.path.join(DATA_DIR, "media") + MEDIA_BASE_URL = values.Value( + None, environ_name="MEDIA_BASE_URL", environ_prefix=None + ) + + SITE_ID = 1 + + STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": values.Value( + "whitenoise.storage.CompressedManifestStaticFilesStorage", + environ_name="STORAGES_STATICFILES_BACKEND", + ), + }, + } + + # Maximum size of the request body in memory. + # This is used to limit the size of the request body in memory. + # This also limits the size of the file that can be uploaded to the server. + DATA_UPLOAD_MAX_MEMORY_SIZE = values.PositiveIntegerValue( + 2 * (2**30), # 2GB + environ_name="DATA_UPLOAD_MAX_MEMORY_SIZE", + environ_prefix=None, + ) + + # Internationalization + # https://docs.djangoproject.com/en/3.1/topics/i18n/ + + # Languages + LANGUAGE_CODE = values.Value("en-us") + LANGUAGE_COOKIE_NAME = "calendar_language" # cookie & language is set from frontend + + DRF_NESTED_MULTIPART_PARSER = { + # output of parser is converted to querydict + # if is set to False, dict python is returned + "querydict": False, + } + + # Careful! Languages should be ordered by priority, as this tuple is used to get + # fallback/default languages throughout the app. + LANGUAGES = values.SingleNestedTupleValue( + ( + ("en-us", _("English")), + ("fr-fr", _("French")), + ("de-de", _("German")), + ("nl-nl", _("Dutch")), + ) + ) + + LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),) + + TIME_ZONE = "UTC" + USE_I18N = True + USE_TZ = True + + # Templates + TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [os.path.join(BASE_DIR, "templates")], + "OPTIONS": { + "context_processors": [ + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + "django.template.context_processors.csrf", + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.request", + "django.template.context_processors.tz", + ], + "loaders": [ + "django.template.loaders.filesystem.Loader", + "django.template.loaders.app_directories.Loader", + ], + }, + }, + ] + + MIDDLEWARE = [ + "django.middleware.security.SecurityMiddleware", + "whitenoise.middleware.WhiteNoiseMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.locale.LocaleMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "corsheaders.middleware.CorsMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + ] + + AUTHENTICATION_BACKENDS = [ + "django.contrib.auth.backends.ModelBackend", + "core.authentication.backends.OIDCAuthenticationBackend", + ] + + # Django applications from the highest priority to the lowest + INSTALLED_APPS = [ + "core", + "drf_spectacular", + "drf_standardized_errors", + # Third party apps + "corsheaders", + "django_celery_beat", + "django_filters", + "rest_framework", + "rest_framework_api_key", + "parler", + # Django + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.postgres", + "django.contrib.sessions", + "django.contrib.sites", + "django.contrib.messages", + "django.contrib.staticfiles", + # OIDC third party + "mozilla_django_oidc", + ] + + # Cache + CACHES = { + "default": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": values.Value( + "redis://redis:6379/0", + environ_name="REDIS_URL", + environ_prefix=None, + ), + "TIMEOUT": values.IntegerValue( + 30, # timeout in seconds + environ_name="CACHES_DEFAULT_TIMEOUT", + environ_prefix=None, + ), + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + }, + "KEY_PREFIX": values.Value( + "calendar", + environ_name="CACHES_DEFAULT_KEY_PREFIX", + environ_prefix=None, + ), + }, + "session": { + "BACKEND": "django_redis.cache.RedisCache", + "LOCATION": values.Value( + "redis://redis:6379/0", + environ_name="REDIS_URL", + environ_prefix=None, + ), + "TIMEOUT": values.IntegerValue( + 30, # timeout in seconds + environ_name="CACHES_SESSION_TIMEOUT", + environ_prefix=None, + ), + "OPTIONS": { + "CLIENT_CLASS": "django_redis.client.DefaultClient", + }, + }, + } + + REST_FRAMEWORK = { + "DEFAULT_AUTHENTICATION_CLASSES": ( + "mozilla_django_oidc.contrib.drf.OIDCAuthentication", + "rest_framework.authentication.SessionAuthentication", + ), + "DEFAULT_PARSER_CLASSES": [ + "rest_framework.parsers.JSONParser", + "nested_multipart_parser.drf.DrfNestedParser", + ], + "DEFAULT_RENDERER_CLASSES": [ + # 🔒️ Disable BrowsableAPIRenderer which provides forms allowing a user to + # see all the data in the database (ie a serializer with a ForeignKey field + # will generate a form with a field with all possible values of the FK). + "rest_framework.renderers.JSONRenderer", + ], + "EXCEPTION_HANDLER": "core.api.exception_handler", + "DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination", + "PAGE_SIZE": 20, + "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning", + "DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema", + "DEFAULT_THROTTLE_CLASSES": ["rest_framework.throttling.ScopedRateThrottle"], + "DEFAULT_THROTTLE_RATES": { + "user_list_sustained": values.Value( + default="180/hour", + environ_name="API_USERS_LIST_THROTTLE_RATE_SUSTAINED", + environ_prefix=None, + ), + "user_list_burst": values.Value( + default="30/minute", + environ_name="API_USERS_LIST_THROTTLE_RATE_BURST", + environ_prefix=None, + ), + }, + } + + MAX_PAGE_SIZE = values.PositiveIntegerValue( + 200, environ_name="MAX_PAGE_SIZE", environ_prefix=None + ) + + SPECTACULAR_SETTINGS = { + "TITLE": "calendar API", + "DESCRIPTION": "This is the calendar API schema.", + "VERSION": "1.0.0", + "SERVE_INCLUDE_SCHEMA": False, + "ENABLE_DJANGO_DEPLOY_CHECK": values.BooleanValue( + default=False, + environ_name="SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK", + ), + "COMPONENT_SPLIT_REQUEST": True, + # OTHER SETTINGS + "SWAGGER_UI_DIST": "SIDECAR", # shorthand to use the sidecar instead + "SWAGGER_UI_FAVICON_HREF": "SIDECAR", + "REDOC_DIST": "SIDECAR", + } + + TRASHBIN_CUTOFF_DAYS = values.Value( + 30, environ_name="TRASHBIN_CUTOFF_DAYS", environ_prefix=None + ) + + AUTH_USER_MODEL = "core.User" + INVITATION_VALIDITY_DURATION = 604800 # 7 days, in seconds + + # CORS + CORS_ALLOW_CREDENTIALS = True + CORS_ALLOW_ALL_ORIGINS = values.BooleanValue(False) + CORS_ALLOWED_ORIGINS = values.ListValue([]) + CORS_ALLOWED_ORIGIN_REGEXES = values.ListValue([]) + # Allow CalDAV methods (PROPFIND, REPORT, etc.) + CORS_ALLOW_METHODS = [ + "DELETE", + "GET", + "OPTIONS", + "PATCH", + "POST", + "PUT", + "PROPFIND", + "REPORT", + "MKCOL", + "MKCALENDAR", + ] + # Allow CalDAV headers (case-sensitive for CORS preflight) + CORS_ALLOW_HEADERS = [ + "accept", + "accept-encoding", + "authorization", + "content-type", + "dnt", + "origin", + "user-agent", + "x-csrftoken", + "x-requested-with", + "depth", # CalDAV header (lowercase as sent by browsers) + "if-match", + "if-none-match", + "prefer", + ] + + # Sentry + SENTRY_DSN = values.Value(None, environ_name="SENTRY_DSN", environ_prefix=None) + + # Frontend + FRONTEND_THEME = values.Value( + None, environ_name="FRONTEND_THEME", environ_prefix=None + ) + FRONTEND_MORE_LINK = values.Value( + None, + environ_name="FRONTEND_MORE_LINK", + environ_prefix=None, + ) + FRONTEND_FEEDBACK_BUTTON_SHOW = values.BooleanValue( + default=False, environ_name="FRONTEND_FEEDBACK_BUTTON_SHOW", environ_prefix=None + ) + # For instance, you might want to bind this button to an external library to trigger survey instead of the build in feedback modal. + FRONTEND_FEEDBACK_BUTTON_IDLE = values.BooleanValue( + default=False, environ_name="FRONTEND_FEEDBACK_BUTTON_IDLE", environ_prefix=None + ) + FRONTEND_FEEDBACK_ITEMS = values.DictValue( + {}, environ_name="FRONTEND_FEEDBACK_ITEMS", environ_prefix=None + ) + FRONTEND_FEEDBACK_MESSAGES_WIDGET_ENABLED = values.BooleanValue( + default=False, + environ_name="FRONTEND_FEEDBACK_MESSAGES_WIDGET_ENABLED", + environ_prefix=None, + ) + FRONTEND_FEEDBACK_MESSAGES_WIDGET_API_URL = values.Value( + None, + environ_name="FRONTEND_FEEDBACK_MESSAGES_WIDGET_API_URL", + environ_prefix=None, + ) + FRONTEND_FEEDBACK_MESSAGES_WIDGET_CHANNEL = values.Value( + None, + environ_name="FRONTEND_FEEDBACK_MESSAGES_WIDGET_CHANNEL", + environ_prefix=None, + ) + FRONTEND_FEEDBACK_MESSAGES_WIDGET_PATH = values.Value( + None, environ_name="FRONTEND_FEEDBACK_MESSAGES_WIDGET_PATH", environ_prefix=None + ) + FRONTEND_HIDE_GAUFRE = values.BooleanValue( + default=False, environ_name="FRONTEND_HIDE_GAUFRE", environ_prefix=None + ) + THEME_CUSTOMIZATION_FILE_PATH = values.Value( + os.path.join(BASE_DIR, "calendars/configuration/theme/default.json"), + environ_name="THEME_CUSTOMIZATION_FILE_PATH", + environ_prefix=None, + ) + THEME_CUSTOMIZATION_CACHE_TIMEOUT = values.Value( + 60 * 60 * 24, + environ_name="THEME_CUSTOMIZATION_CACHE_TIMEOUT", + environ_prefix=None, + ) + + # Easy thumbnails + THUMBNAIL_EXTENSION = "webp" + THUMBNAIL_TRANSPARENCY_EXTENSION = "webp" + THUMBNAIL_DEFAULT_STORAGE_ALIAS = "default" + THUMBNAIL_ALIASES = {} + + # Celery + CELERY_BROKER_URL = values.Value("redis://redis:6379/0") + CELERY_BROKER_TRANSPORT_OPTIONS = values.DictValue({}) + CELERY_BEAT_SCHEDULER = "django_celery_beat.schedulers:DatabaseScheduler" + + # Session + SESSION_ENGINE = "django.contrib.sessions.backends.cache" + SESSION_CACHE_ALIAS = "session" + SESSION_COOKIE_AGE = 60 * 60 * 12 + + # OIDC - Authorization Code Flow + OIDC_CREATE_USER = values.BooleanValue( + default=True, + environ_name="OIDC_CREATE_USER", + ) + OIDC_CALLBACK_CLASS = "core.authentication.views.OIDCAuthenticationCallbackView" + OIDC_RP_SIGN_ALGO = values.Value( + "RS256", environ_name="OIDC_RP_SIGN_ALGO", environ_prefix=None + ) + OIDC_RP_CLIENT_ID = values.Value( + "calendar", environ_name="OIDC_RP_CLIENT_ID", environ_prefix=None + ) + OIDC_RP_CLIENT_SECRET = SecretFileValue( + None, + environ_name="OIDC_RP_CLIENT_SECRET", + environ_prefix=None, + ) + OIDC_OP_JWKS_ENDPOINT = values.Value( + environ_name="OIDC_OP_JWKS_ENDPOINT", environ_prefix=None + ) + OIDC_OP_AUTHORIZATION_ENDPOINT = values.Value( + environ_name="OIDC_OP_AUTHORIZATION_ENDPOINT", environ_prefix=None + ) + OIDC_OP_TOKEN_ENDPOINT = values.Value( + None, environ_name="OIDC_OP_TOKEN_ENDPOINT", environ_prefix=None + ) + OIDC_OP_USER_ENDPOINT = values.Value( + None, environ_name="OIDC_OP_USER_ENDPOINT", environ_prefix=None + ) + OIDC_OP_LOGOUT_ENDPOINT = values.Value( + None, environ_name="OIDC_OP_LOGOUT_ENDPOINT", environ_prefix=None + ) + OIDC_REDIRECT_FIELD_NAME = values.Value( + "returnTo", environ_name="OIDC_REDIRECT_FIELD_NAME", environ_prefix=None + ) + OIDC_AUTH_REQUEST_EXTRA_PARAMS = values.DictValue( + {}, environ_name="OIDC_AUTH_REQUEST_EXTRA_PARAMS", environ_prefix=None + ) + OIDC_RP_SCOPES = values.Value( + "openid email", environ_name="OIDC_RP_SCOPES", environ_prefix=None + ) + LOGIN_REDIRECT_URL = values.Value( + None, environ_name="LOGIN_REDIRECT_URL", environ_prefix=None + ) + LOGIN_REDIRECT_URL_FAILURE = values.Value( + None, environ_name="LOGIN_REDIRECT_URL_FAILURE", environ_prefix=None + ) + LOGOUT_REDIRECT_URL = values.Value( + None, environ_name="LOGOUT_REDIRECT_URL", environ_prefix=None + ) + OIDC_USE_NONCE = values.BooleanValue( + default=True, environ_name="OIDC_USE_NONCE", environ_prefix=None + ) + OIDC_REDIRECT_REQUIRE_HTTPS = values.BooleanValue( + default=False, environ_name="OIDC_REDIRECT_REQUIRE_HTTPS", environ_prefix=None + ) + OIDC_REDIRECT_ALLOWED_HOSTS = values.ListValue( + default=[], environ_name="OIDC_REDIRECT_ALLOWED_HOSTS", environ_prefix=None + ) + OIDC_STORE_ID_TOKEN = values.BooleanValue( + default=True, environ_name="OIDC_STORE_ID_TOKEN", environ_prefix=None + ) + OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION = values.BooleanValue( + default=True, + environ_name="OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION", + environ_prefix=None, + ) + + OIDC_STORE_ACCESS_TOKEN = values.BooleanValue( + default=False, environ_name="OIDC_STORE_ACCESS_TOKEN", environ_prefix=None + ) + OIDC_STORE_REFRESH_TOKEN = values.BooleanValue( + default=False, environ_name="OIDC_STORE_REFRESH_TOKEN", environ_prefix=None + ) + OIDC_STORE_REFRESH_TOKEN_KEY = values.Value( + default=None, + environ_name="OIDC_STORE_REFRESH_TOKEN_KEY", + environ_prefix=None, + ) + + # OIDC claims to store + OIDC_STORE_CLAIMS = values.ListValue( + default=[], + environ_name="OIDC_STORE_CLAIMS", + environ_prefix=None, + ) + + # WARNING: Enabling this setting allows multiple user accounts to share the same email + # address. This may cause security issues and is not recommended for production use when + # email is activated as fallback for identification (see previous setting). + OIDC_ALLOW_DUPLICATE_EMAILS = values.BooleanValue( + default=False, + environ_name="OIDC_ALLOW_DUPLICATE_EMAILS", + environ_prefix=None, + ) + + OIDC_USER_INFO = values.ListValue( + default=values.ListValue( # retrocompatibility + default=[], + environ_name="USER_OIDC_ESSENTIAL_CLAIMS", + environ_prefix=None, + ), + environ_name="OIDC_USER_INFO", + environ_prefix=None, + ) + + OIDC_USERINFO_FULLNAME_FIELDS = values.ListValue( + default=["first_name", "last_name"], + environ_name="OIDC_USERINFO_FULLNAME_FIELDS", + environ_prefix=None, + ) + OIDC_USERINFO_SHORTNAME_FIELD = values.Value( + default="first_name", + environ_name="OIDC_USERINFO_SHORTNAME_FIELD", + environ_prefix=None, + ) + + # OIDC Resource Server + + OIDC_RESOURCE_SERVER_ENABLED = values.BooleanValue( + default=False, environ_name="OIDC_RESOURCE_SERVER_ENABLED", environ_prefix=None + ) + + OIDC_RS_BACKEND_CLASS = values.Value( + "lasuite.oidc_resource_server.backend.ResourceServerBackend", + environ_name="OIDC_RS_BACKEND_CLASS", + environ_prefix=None, + ) + + OIDC_OP_URL = values.Value(None, environ_name="OIDC_OP_URL", environ_prefix=None) + + OIDC_VERIFY_SSL = values.BooleanValue( + default=True, environ_name="OIDC_VERIFY_SSL", environ_prefix=None + ) + + OIDC_TIMEOUT = values.PositiveIntegerValue( + 3, environ_name="OIDC_TIMEOUT", environ_prefix=None + ) + + OIDC_PROXY = values.Value(None, environ_name="OIDC_PROXY", environ_prefix=None) + + OIDC_OP_INTROSPECTION_ENDPOINT = values.Value( + None, environ_name="OIDC_OP_INTROSPECTION_ENDPOINT", environ_prefix=None + ) + + OIDC_RS_CLIENT_ID = values.Value( + None, environ_name="OIDC_RS_CLIENT_ID", environ_prefix=None + ) + + OIDC_RS_CLIENT_SECRET = values.Value( + None, environ_name="OIDC_RS_CLIENT_SECRET", environ_prefix=None + ) + + OIDC_RS_AUDIENCE_CLAIM = values.Value( + "client_id", environ_name="OIDC_RS_AUDIENCE_CLAIM", environ_prefix=None + ) + + OIDC_RS_ENCRYPTION_ENCODING = values.Value( + "A256GCM", environ_name="OIDC_RS_ENCRYPTION_ENCODING", environ_prefix=None + ) + + OIDC_RS_ENCRYPTION_ALGO = values.Value( + "RSA-OAEP", environ_name="OIDC_RS_ENCRYPTION_ALGO", environ_prefix=None + ) + + OIDC_RS_SIGNING_ALGO = values.Value( + "ES256", environ_name="OIDC_RS_SIGNING_ALGO", environ_prefix=None + ) + + OIDC_RS_SCOPES = values.ListValue( + ["openid"], environ_name="OIDC_RS_SCOPES", environ_prefix=None + ) + + OIDC_RS_ALLOWED_AUDIENCES = values.ListValue( + default=[], + environ_name="OIDC_RS_ALLOWED_AUDIENCES", + environ_prefix=None, + ) + + # External API Configuration + # Configure available routes and actions for external_api endpoints + EXTERNAL_API = values.DictValue( + default={ + "users": { + "enabled": True, + "actions": ["get_me"], + }, + }, + environ_name="EXTERNAL_API", + environ_prefix=None, + ) + + OIDC_RS_PRIVATE_KEY_STR = values.Value( + default=None, + environ_name="OIDC_RS_PRIVATE_KEY_STR", + environ_prefix=None, + ) + OIDC_RS_ENCRYPTION_KEY_TYPE = values.Value( + default="RSA", + environ_name="OIDC_RS_ENCRYPTION_KEY_TYPE", + environ_prefix=None, + ) + + ALLOW_LOGOUT_GET_METHOD = values.BooleanValue( + default=True, environ_name="ALLOW_LOGOUT_GET_METHOD", environ_prefix=None + ) + + # Logging + # We want to make it easy to log to console but by default we log production + # to Sentry and don't want to log to console. + LOGGING = { + "version": 1, + "disable_existing_loggers": False, + "formatters": { + "simple": { + "format": "{asctime} {name} {levelname} {message}", + "style": "{", + }, + }, + "handlers": { + "console": { + "class": "logging.StreamHandler", + "formatter": "simple", + }, + }, + # Override root logger to send it to console + "root": { + "handlers": ["console"], + "level": values.Value( + "INFO", environ_name="LOGGING_LEVEL_LOGGERS_ROOT", environ_prefix=None + ), + }, + "loggers": { + "core": { + "handlers": ["console"], + "level": values.Value( + "INFO", + environ_name="LOGGING_LEVEL_LOGGERS_APP", + environ_prefix=None, + ), + "propagate": True, + }, + }, + } + + API_USERS_LIST_LIMIT = values.PositiveIntegerValue( + default=5, + environ_name="API_USERS_LIST_LIMIT", + environ_prefix=None, + ) + + # Storage compute + + # pylint: disable=invalid-name + @property + def ENVIRONMENT(self): + """Environment in which the application is launched.""" + return self.__class__.__name__.lower() + + # pylint: disable=invalid-name + @property + def RELEASE(self): + """ + Return the release information. + + Delegate to the module function to enable easier testing. + """ + return get_release() + + # pylint: disable=invalid-name + @property + def PARLER_LANGUAGES(self): + """ + Return languages for Parler computed from the LANGUAGES and LANGUAGE_CODE settings. + """ + return { + self.SITE_ID: tuple({"code": code} for code, _name in self.LANGUAGES), + "default": { + "fallbacks": [self.LANGUAGE_CODE], + "hide_untranslated": False, + }, + } + + @classmethod + def post_setup(cls): + """Post setup configuration. + This is the place where you can configure settings that require other + settings to be loaded. + """ + super().post_setup() + + # The SENTRY_DSN setting should be available to activate sentry for an environment + if cls.SENTRY_DSN is not None: + sentry_sdk.init( + dsn=cls.SENTRY_DSN, + environment=cls.__name__.lower(), + release=get_release(), + integrations=[DjangoIntegration()], + ) + sentry_sdk.set_tag("application", "backend") + + if ( + cls.OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION + and cls.OIDC_ALLOW_DUPLICATE_EMAILS + ): + raise ValueError( + "Both OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION and " + "OIDC_ALLOW_DUPLICATE_EMAILS cannot be set to True simultaneously. " + ) + + +class Build(Base): + """Settings used when the application is built. + + This environment should not be used to run the application. Just to build it with non-blocking + settings. + """ + + SESSION_CACHE_ALIAS = "default" + CACHES = { + "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, + } + SECRET_KEY = values.Value("DummyKey") + STORAGES = { + "default": { + "BACKEND": "django.core.files.storage.FileSystemStorage", + }, + "staticfiles": { + "BACKEND": values.Value( + "whitenoise.storage.CompressedManifestStaticFilesStorage", + environ_name="STORAGES_STATICFILES_BACKEND", + ), + }, + } + + +class Development(Base): + """ + Development environment settings + + We set DEBUG to True and configure the server to respond from all hosts. + """ + + ALLOWED_HOSTS = ["*"] + CORS_ALLOW_ALL_ORIGINS = True + CSRF_TRUSTED_ORIGINS = [ + "http://localhost:8920", + ] + DEBUG = True + LOAD_E2E_URLS = True + + SESSION_COOKIE_NAME = "calendar_sessionid" + + USE_SWAGGER = True + + DEBUG_TOOLBAR_CONFIG = { + "SHOW_TOOLBAR_CALLBACK": lambda request: True, + } + + def __init__(self): + # pylint: disable=invalid-name + self.MIDDLEWARE += ["debug_toolbar.middleware.DebugToolbarMiddleware"] + # pylint: disable=invalid-name + self.INSTALLED_APPS += [ + "django_extensions", + "drf_spectacular_sidecar", + "debug_toolbar", + "e2e", + ] + + +class Test(Base): + """Test environment settings""" + + SESSION_CACHE_ALIAS = "default" + CACHES = { + "default": {"BACKEND": "django.core.cache.backends.locmem.LocMemCache"}, + } + + PASSWORD_HASHERS = [ + "django.contrib.auth.hashers.MD5PasswordHasher", + ] + USE_SWAGGER = True + + CELERY_TASK_ALWAYS_EAGER = values.BooleanValue(True) + + OIDC_STORE_ACCESS_TOKEN = False + OIDC_STORE_REFRESH_TOKEN = False + + def __init__(self): + # pylint: disable=invalid-name + self.INSTALLED_APPS += ["drf_spectacular_sidecar", "e2e"] + + +class ContinuousIntegration(Test): + """ + Continuous Integration environment settings + + nota bene: it should inherit from the Test environment. + """ + + +class Production(Base): + """ + Production environment settings + + You must define the ALLOWED_HOSTS environment variable in Production + configuration (and derived configurations): + ALLOWED_HOSTS=["foo.com", "foo.fr"] + """ + + # Security + # Add allowed host from environment variables. + # The machine hostname is added by default, + # it makes the application pingable by a load balancer on the same machine by example + ALLOWED_HOSTS = [ + *values.ListValue([], environ_name="ALLOWED_HOSTS"), + gethostbyname(gethostname()), + ] + CSRF_TRUSTED_ORIGINS = values.ListValue([]) + SECURE_BROWSER_XSS_FILTER = True + SECURE_CONTENT_TYPE_NOSNIFF = True + + # SECURE_PROXY_SSL_HEADER allows to fix the scheme in Django's HttpRequest + # object when your application is behind a reverse proxy. + # + # Keep this SECURE_PROXY_SSL_HEADER configuration only if : + # - your Django app is behind a proxy. + # - your proxy strips the X-Forwarded-Proto header from all incoming requests + # - Your proxy sets the X-Forwarded-Proto header and sends it to Django + # + # In other cases, you should comment the following line to avoid security issues. + # SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") + SECURE_HSTS_SECONDS = 60 + SECURE_HSTS_PRELOAD = True + SECURE_HSTS_INCLUDE_SUBDOMAINS = True + SECURE_SSL_REDIRECT = True + SECURE_REDIRECT_EXEMPT = [ + "^__lbheartbeat__", + "^__heartbeat__", + ] + + # Modern browsers require to have the `secure` attribute on cookies with `Samesite=none` + CSRF_COOKIE_SECURE = True + SESSION_COOKIE_SECURE = True + + # Privacy + SECURE_REFERRER_POLICY = "same-origin" + + +class Feature(Production): + """ + Feature environment settings + + nota bene: it should inherit from the Production environment. + """ + + +class Staging(Production): + """ + Staging environment settings + + nota bene: it should inherit from the Production environment. + """ + + +class PreProduction(Production): + """ + Pre-production environment settings + + nota bene: it should inherit from the Production environment. + """ diff --git a/src/backend/calendars/urls.py b/src/backend/calendars/urls.py new file mode 100644 index 0000000..8c32c8d --- /dev/null +++ b/src/backend/calendars/urls.py @@ -0,0 +1,58 @@ +"""URL configuration for the calendars project""" + +from django.conf import settings +from django.conf.urls.static import static +from django.contrib import admin +from django.contrib.staticfiles.urls import staticfiles_urlpatterns +from django.urls import include, path, re_path + +from drf_spectacular.views import ( + SpectacularJSONAPIView, + SpectacularRedocView, + SpectacularSwaggerView, +) + +from core.api.viewsets_caldav import CalDAVDiscoveryView + +urlpatterns = [ + path("admin/", admin.site.urls), + # CalDAV discovery - must be at root level per RFC 6764 + path(".well-known/caldav", CalDAVDiscoveryView.as_view(), name="caldav-discovery"), + path("", include("core.urls")), +] + +if settings.DEBUG: + from debug_toolbar.toolbar import debug_toolbar_urls + + urlpatterns = ( + urlpatterns + + staticfiles_urlpatterns() + + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) + + debug_toolbar_urls() + ) + +if settings.LOAD_E2E_URLS: + urlpatterns += [path("", include("e2e.urls"))] + + +if settings.USE_SWAGGER or settings.DEBUG: + urlpatterns += [ + path( + f"api/{settings.API_VERSION}/swagger.json", + SpectacularJSONAPIView.as_view( + api_version=settings.API_VERSION, + urlconf="core.urls", + ), + name="client-api-schema", + ), + path( + f"api/{settings.API_VERSION}/swagger/", + SpectacularSwaggerView.as_view(url_name="client-api-schema"), + name="swagger-ui-schema", + ), + re_path( + f"api/{settings.API_VERSION}/redoc/", + SpectacularRedocView.as_view(url_name="client-api-schema"), + name="redoc-schema", + ), + ] diff --git a/src/backend/calendars/wsgi.py b/src/backend/calendars/wsgi.py new file mode 100644 index 0000000..69344b5 --- /dev/null +++ b/src/backend/calendars/wsgi.py @@ -0,0 +1,17 @@ +""" +WSGI config for the calendars project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from configurations.wsgi import get_wsgi_application + +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calendars.settings") +os.environ.setdefault("DJANGO_CONFIGURATION", "Development") + +application = get_wsgi_application() diff --git a/src/backend/core/__init__.py b/src/backend/core/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/admin.py b/src/backend/core/admin.py new file mode 100644 index 0000000..1efc8ae --- /dev/null +++ b/src/backend/core/admin.py @@ -0,0 +1,93 @@ +"""Admin classes and registrations for core app.""" + +from django.contrib import admin +from django.contrib.auth import admin as auth_admin +from django.utils.translation import gettext_lazy as _ + +from . import models + + +@admin.register(models.User) +class UserAdmin(auth_admin.UserAdmin): + """Admin class for the User model""" + + fieldsets = ( + ( + None, + { + "fields": ( + "id", + "admin_email", + "password", + ) + }, + ), + ( + _("Personal info"), + { + "fields": ( + "sub", + "email", + "full_name", + "short_name", + "language", + "timezone", + ) + }, + ), + ( + _("Permissions"), + { + "fields": ( + "is_active", + "is_device", + "is_staff", + "is_superuser", + "groups", + "user_permissions", + ), + }, + ), + (_("Important dates"), {"fields": ("created_at", "updated_at")}), + ) + add_fieldsets = ( + ( + None, + { + "classes": ("wide",), + "fields": ("email", "password1", "password2"), + }, + ), + ) + list_display = ( + "id", + "sub", + "full_name", + "admin_email", + "email", + "is_active", + "is_staff", + "is_superuser", + "is_device", + "created_at", + "updated_at", + ) + list_filter = ("is_staff", "is_superuser", "is_device", "is_active") + ordering = ( + "is_active", + "-is_superuser", + "-is_staff", + "-is_device", + "-updated_at", + "full_name", + ) + readonly_fields = ( + "id", + "sub", + "email", + "full_name", + "short_name", + "created_at", + "updated_at", + ) + search_fields = ("id", "sub", "admin_email", "email", "full_name") diff --git a/src/backend/core/api/__init__.py b/src/backend/core/api/__init__.py new file mode 100644 index 0000000..6fcdb8b --- /dev/null +++ b/src/backend/core/api/__init__.py @@ -0,0 +1,34 @@ +"""Calendars core API endpoints""" + +from django.conf import settings +from django.core.exceptions import ValidationError as DjangoValidationError + +from drf_standardized_errors.handler import exception_handler as drf_exception_handler +from rest_framework import exceptions as drf_exceptions +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework.serializers import as_serializer_error + + +def exception_handler(exc, context): + """Handle Django ValidationError as an accepted exception. + + For the parameters, see ``exception_handler`` + This code comes from twidi's gist: + https://gist.github.com/twidi/9d55486c36b6a51bdcb05ce3a763e79f + """ + if isinstance(exc, DjangoValidationError): + exc = drf_exceptions.ValidationError(as_serializer_error(exc)) + + return drf_exception_handler(exc, context) + + +# pylint: disable=unused-argument +@api_view(["GET"]) +def get_frontend_configuration(request): + """Returns the frontend configuration dict as configured in settings.""" + frontend_configuration = { + "LANGUAGE_CODE": settings.LANGUAGE_CODE, + } + frontend_configuration.update(settings.FRONTEND_CONFIGURATION) + return Response(frontend_configuration) diff --git a/src/backend/core/api/fields.py b/src/backend/core/api/fields.py new file mode 100644 index 0000000..1125622 --- /dev/null +++ b/src/backend/core/api/fields.py @@ -0,0 +1,25 @@ +"""A JSONField for DRF to handle serialization/deserialization.""" + +import json + +from rest_framework import serializers + + +class JSONField(serializers.Field): + """ + A custom field for handling JSON data. + """ + + def to_representation(self, value): + """ + Convert the JSON string to a Python dictionary for serialization. + """ + return value + + def to_internal_value(self, data): + """ + Convert the Python dictionary to a JSON string for deserialization. + """ + if data is None: + return None + return json.dumps(data) diff --git a/src/backend/core/api/permissions.py b/src/backend/core/api/permissions.py new file mode 100644 index 0000000..f94a19d --- /dev/null +++ b/src/backend/core/api/permissions.py @@ -0,0 +1,79 @@ +"""Permission handlers for the calendars core app.""" + +from django.core import exceptions + +from rest_framework import permissions + +ACTION_FOR_METHOD_TO_PERMISSION = { + "versions_detail": {"DELETE": "versions_destroy", "GET": "versions_retrieve"}, + "children": {"GET": "children_list", "POST": "children_create"}, +} + + +class IsAuthenticated(permissions.BasePermission): + """ + Allows access only to authenticated users. Alternative method checking the presence + of the auth token to avoid hitting the database. + """ + + def has_permission(self, request, view): + return bool(request.auth) or request.user.is_authenticated + + +class IsAuthenticatedOrSafe(IsAuthenticated): + """Allows access to authenticated users (or anonymous users but only on safe methods).""" + + def has_permission(self, request, view): + if request.method in permissions.SAFE_METHODS: + return True + return super().has_permission(request, view) + + +class IsSelf(IsAuthenticated): + """ + Allows access only to authenticated users. Alternative method checking the presence + of the auth token to avoid hitting the database. + """ + + def has_object_permission(self, request, view, obj): + """Write permissions are only allowed to the user itself.""" + return obj == request.user + + +class IsOwnedOrPublic(IsAuthenticated): + """ + Allows access to authenticated users only for objects that are owned or not related + to any user via the "owner" field. + """ + + def has_object_permission(self, request, view, obj): + """Unsafe permissions are only allowed for the owner of the object.""" + if obj.owner == request.user: + return True + + if request.method in permissions.SAFE_METHODS and obj.owner is None: + return True + + try: + return obj.user == request.user + except exceptions.ObjectDoesNotExist: + return False + + +class AccessPermission(permissions.BasePermission): + """Permission class for access objects.""" + + def has_permission(self, request, view): + return request.user.is_authenticated or view.action not in [ + "create", + ] + + def has_object_permission(self, request, view, obj): + """Check permission for a given object.""" + abilities = obj.get_abilities(request.user) + action = view.action + try: + action = ACTION_FOR_METHOD_TO_PERMISSION[view.action][request.method] + except KeyError: + pass + return abilities.get(action, False) diff --git a/src/backend/core/api/serializers.py b/src/backend/core/api/serializers.py new file mode 100644 index 0000000..4752ca1 --- /dev/null +++ b/src/backend/core/api/serializers.py @@ -0,0 +1,155 @@ +"""Client serializers for the calendars core app.""" + +import json +from datetime import timedelta + +from django.conf import settings +from django.db.models import Q +from django.utils.translation import gettext_lazy as _ + +from rest_framework import exceptions, serializers + +from core import models + + +class UserLiteSerializer(serializers.ModelSerializer): + """Serialize users with limited fields.""" + + class Meta: + model = models.User + fields = ["id", "full_name", "short_name"] + read_only_fields = ["id", "full_name", "short_name"] + + +class BaseAccessSerializer(serializers.ModelSerializer): + """Serialize template accesses.""" + + abilities = serializers.SerializerMethodField(read_only=True) + + def update(self, instance, validated_data): + """Make "user" field is readonly but only on update.""" + validated_data.pop("user", None) + return super().update(instance, validated_data) + + def get_abilities(self, access) -> dict: + """Return abilities of the logged-in user on the instance.""" + request = self.context.get("request") + if request: + return access.get_abilities(request.user) + return {} + + def validate(self, attrs): + """ + Check access rights specific to writing (create/update) + """ + request = self.context.get("request") + user = getattr(request, "user", None) + role = attrs.get("role") + + # Update + if self.instance: + can_set_role_to = self.instance.get_abilities(user)["set_role_to"] + + if role and role not in can_set_role_to: + message = ( + f"You are only allowed to set role to {', '.join(can_set_role_to)}" + if can_set_role_to + else "You are not allowed to set this role for this template." + ) + raise exceptions.PermissionDenied(message) + + # Create + else: + try: + resource_id = self.context["resource_id"] + except KeyError as exc: + raise exceptions.ValidationError( + "You must set a resource ID in kwargs to create a new access." + ) from exc + + if not self.Meta.model.objects.filter( # pylint: disable=no-member + Q(user=user) | Q(team__in=user.teams), + role__in=[models.RoleChoices.OWNER, models.RoleChoices.ADMIN], + **{self.Meta.resource_field_name: resource_id}, # pylint: disable=no-member + ).exists(): + raise exceptions.PermissionDenied( + "You are not allowed to manage accesses for this resource." + ) + + if ( + role == models.RoleChoices.OWNER + and not self.Meta.model.objects.filter( # pylint: disable=no-member + Q(user=user) | Q(team__in=user.teams), + role=models.RoleChoices.OWNER, + **{self.Meta.resource_field_name: resource_id}, # pylint: disable=no-member + ).exists() + ): + raise exceptions.PermissionDenied( + "Only owners of a resource can assign other users as owners." + ) + + # pylint: disable=no-member + attrs[f"{self.Meta.resource_field_name}_id"] = self.context["resource_id"] + return attrs + + +class UserSerializer(serializers.ModelSerializer): + """Serialize users.""" + + class Meta: + model = models.User + fields = [ + "id", + "email", + "full_name", + "short_name", + "language", + ] + read_only_fields = ["id", "email", "full_name", "short_name"] + + +class UserMeSerializer(UserSerializer): + """Serialize users for me endpoint.""" + + class Meta: + model = models.User + fields = UserSerializer.Meta.fields + read_only_fields = UserSerializer.Meta.read_only_fields + + +# CalDAV serializers +class CalendarSerializer(serializers.ModelSerializer): + """Serializer for Calendar model.""" + + class Meta: + model = models.Calendar + fields = [ + "id", + "name", + "color", + "description", + "is_default", + "is_visible", + "created_at", + "updated_at", + ] + read_only_fields = ["id", "is_default", "created_at", "updated_at"] + + +class CalendarCreateSerializer(serializers.ModelSerializer): + """Serializer for creating a Calendar.""" + + class Meta: + model = models.Calendar + fields = ["name", "color", "description"] + + +class CalendarShareSerializer(serializers.ModelSerializer): + """Serializer for CalendarShare model.""" + + shared_with_email = serializers.EmailField(write_only=True) + + class Meta: + model = models.CalendarShare + fields = ["id", "shared_with_email", "permission", "is_visible", "created_at"] + read_only_fields = ["id", "created_at"] diff --git a/src/backend/core/api/viewsets.py b/src/backend/core/api/viewsets.py new file mode 100644 index 0000000..5cef50c --- /dev/null +++ b/src/backend/core/api/viewsets.py @@ -0,0 +1,397 @@ +"""API endpoints""" +# pylint: disable=too-many-lines + +import json +import logging +import re +from urllib.parse import unquote, urlparse + +from django.conf import settings +from django.core.cache import cache +from django.core.exceptions import ValidationError +from django.db import models as db +from django.db import transaction +from django.urls import reverse +from django.utils.decorators import method_decorator +from django.utils.text import slugify + +import rest_framework as drf +from corsheaders.middleware import ( + ACCESS_CONTROL_ALLOW_METHODS, + ACCESS_CONTROL_ALLOW_ORIGIN, +) +from lasuite.oidc_login.decorators import refresh_oidc_access_token +from rest_framework import filters, mixins, status, viewsets +from rest_framework import response as drf_response +from rest_framework.decorators import action +from rest_framework.permissions import AllowAny, IsAuthenticated +from rest_framework.throttling import UserRateThrottle +from rest_framework_api_key.permissions import HasAPIKey + +from core import enums, models +from core.services.caldav_service import CalendarService + +from . import permissions, serializers + +logger = logging.getLogger(__name__) + + +# pylint: disable=too-many-ancestors + + +class NestedGenericViewSet(viewsets.GenericViewSet): + """ + A generic Viewset aims to be used in a nested route context. + e.g: `/api/v1.0/resource_1//resource_2//` + + It allows to define all url kwargs and lookup fields to perform the lookup. + """ + + lookup_fields: list[str] = ["pk"] + lookup_url_kwargs: list[str] = [] + + def __getattribute__(self, item): + """ + This method is overridden to allow to get the last lookup field or lookup url kwarg + when accessing the `lookup_field` or `lookup_url_kwarg` attribute. This is useful + to keep compatibility with all methods used by the parent class `GenericViewSet`. + """ + if item in ["lookup_field", "lookup_url_kwarg"]: + return getattr(self, item + "s", [None])[-1] + + return super().__getattribute__(item) + + def get_queryset(self): + """ + Get the list of items for this view. + + `lookup_fields` attribute is enumerated here to perform the nested lookup. + """ + queryset = super().get_queryset() + + # The last lookup field is removed to perform the nested lookup as it corresponds + # to the object pk, it is used within get_object method. + lookup_url_kwargs = ( + self.lookup_url_kwargs[:-1] + if self.lookup_url_kwargs + else self.lookup_fields[:-1] + ) + + filter_kwargs = {} + for index, lookup_url_kwarg in enumerate(lookup_url_kwargs): + if lookup_url_kwarg not in self.kwargs: + raise KeyError( + f"Expected view {self.__class__.__name__} to be called with a URL " + f'keyword argument named "{lookup_url_kwarg}". Fix your URL conf, or ' + "set the `.lookup_fields` attribute on the view correctly." + ) + + filter_kwargs.update( + {self.lookup_fields[index]: self.kwargs[lookup_url_kwarg]} + ) + + return queryset.filter(**filter_kwargs) + + +class SerializerPerActionMixin: + """ + A mixin to allow to define serializer classes for each action. + + This mixin is useful to avoid to define a serializer class for each action in the + `get_serializer_class` method. + + Example: + ``` + class MyViewSet(SerializerPerActionMixin, viewsets.GenericViewSet): + serializer_class = MySerializer + list_serializer_class = MyListSerializer + retrieve_serializer_class = MyRetrieveSerializer + ``` + """ + + def get_serializer_class(self): + """ + Return the serializer class to use depending on the action. + """ + if serializer_class := getattr(self, f"{self.action}_serializer_class", None): + return serializer_class + return super().get_serializer_class() + + +class Pagination(drf.pagination.PageNumberPagination): + """Pagination to display no more than 100 objects per page sorted by creation date.""" + + ordering = "-created_on" + max_page_size = settings.MAX_PAGE_SIZE + page_size_query_param = "page_size" + + +class UserListThrottleBurst(UserRateThrottle): + """Throttle for the user list endpoint.""" + + scope = "user_list_burst" + + +class UserListThrottleSustained(UserRateThrottle): + """Throttle for the user list endpoint.""" + + scope = "user_list_sustained" + + +class UserViewSet( + SerializerPerActionMixin, + drf.mixins.UpdateModelMixin, + viewsets.GenericViewSet, + drf.mixins.ListModelMixin, +): + """User ViewSet""" + + permission_classes = [permissions.IsSelf] + queryset = models.User.objects.all().filter(is_active=True) + serializer_class = serializers.UserSerializer + get_me_serializer_class = serializers.UserMeSerializer + pagination_class = None + throttle_classes = [] + + def get_throttles(self): + self.throttle_classes = [] + if self.action == "list": + self.throttle_classes = [UserListThrottleBurst, UserListThrottleSustained] + + return super().get_throttles() + + def get_queryset(self): + """ + Limit listed users by querying the email field. + If query contains "@", search exactly. Otherwise return empty. + """ + queryset = self.queryset + + if self.action != "list": + return queryset + + if not (query := self.request.query_params.get("q", "")) or len(query) < 5: + return queryset.none() + + # For emails, match exactly + if "@" in query: + return queryset.filter(email__iexact=query).order_by("email")[ + : settings.API_USERS_LIST_LIMIT + ] + + # For non-email queries, return empty (no fuzzy search) + return queryset.none() + + @drf.decorators.action( + detail=False, + methods=["get"], + url_name="me", + url_path="me", + ) + def get_me(self, request): + """ + Return information on currently logged user + """ + context = {"request": request} + return drf.response.Response( + self.get_serializer(request.user, context=context).data + ) + + +class ConfigView(drf.views.APIView): + """API ViewSet for sharing some public settings.""" + + permission_classes = [AllowAny] + + def get(self, request): + """ + GET /api/v1.0/config/ + Return a dictionary of public settings. + """ + array_settings = [ + "ENVIRONMENT", + "FRONTEND_THEME", + "FRONTEND_MORE_LINK", + "FRONTEND_FEEDBACK_BUTTON_SHOW", + "FRONTEND_FEEDBACK_BUTTON_IDLE", + "FRONTEND_FEEDBACK_ITEMS", + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_ENABLED", + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_API_URL", + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_CHANNEL", + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_PATH", + "FRONTEND_HIDE_GAUFRE", + "MEDIA_BASE_URL", + "LANGUAGES", + "LANGUAGE_CODE", + "SENTRY_DSN", + ] + dict_settings = {} + for setting in array_settings: + if hasattr(settings, setting): + dict_settings[setting] = getattr(settings, setting) + + dict_settings["theme_customization"] = self._load_theme_customization() + + return drf.response.Response(dict_settings) + + def _load_theme_customization(self): + if not settings.THEME_CUSTOMIZATION_FILE_PATH: + return {} + + cache_key = ( + f"theme_customization_{slugify(settings.THEME_CUSTOMIZATION_FILE_PATH)}" + ) + theme_customization = cache.get(cache_key, {}) + if theme_customization: + return theme_customization + + try: + with open( + settings.THEME_CUSTOMIZATION_FILE_PATH, "r", encoding="utf-8" + ) as f: + theme_customization = json.load(f) + except FileNotFoundError: + logger.error( + "Configuration file not found: %s", + settings.THEME_CUSTOMIZATION_FILE_PATH, + ) + except json.JSONDecodeError: + logger.error( + "Configuration file is not a valid JSON: %s", + settings.THEME_CUSTOMIZATION_FILE_PATH, + ) + else: + cache.set( + cache_key, + theme_customization, + settings.THEME_CUSTOMIZATION_CACHE_TIMEOUT, + ) + + return theme_customization + + +# CalDAV ViewSets +class CalendarViewSet( + mixins.ListModelMixin, + mixins.RetrieveModelMixin, + mixins.CreateModelMixin, + mixins.UpdateModelMixin, + mixins.DestroyModelMixin, + viewsets.GenericViewSet, +): + """ + ViewSet for managing user calendars. + + list: Get all calendars accessible by the user (owned + shared) + retrieve: Get a specific calendar + create: Create a new calendar + update: Update calendar properties + destroy: Delete a calendar + """ + + permission_classes = [IsAuthenticated] + serializer_class = serializers.CalendarSerializer + + def get_queryset(self): + """Return calendars owned by or shared with the current user.""" + user = self.request.user + owned = models.Calendar.objects.filter(owner=user) + shared_ids = models.CalendarShare.objects.filter(shared_with=user).values_list( + "calendar_id", flat=True + ) + shared = models.Calendar.objects.filter(id__in=shared_ids) + return owned.union(shared).order_by("-is_default", "name") + + def get_serializer_class(self): + if self.action == "create": + return serializers.CalendarCreateSerializer + return serializers.CalendarSerializer + + def perform_create(self, serializer): + """Create a new calendar via CalendarService.""" + service = CalendarService() + calendar = service.create_calendar( + user=self.request.user, + name=serializer.validated_data["name"], + color=serializer.validated_data.get("color", "#3174ad"), + ) + # Update the serializer instance with the created calendar + serializer.instance = calendar + + def perform_destroy(self, instance): + """Delete calendar. Prevent deletion of default calendar.""" + if instance.is_default: + raise ValueError("Cannot delete the default calendar.") + if instance.owner != self.request.user: + raise PermissionError("You can only delete your own calendars.") + instance.delete() + + @action(detail=True, methods=["patch"]) + def toggle_visibility(self, request, pk=None): + """Toggle calendar visibility.""" + calendar = self.get_object() + + # Check if it's a shared calendar + share = models.CalendarShare.objects.filter( + calendar=calendar, shared_with=request.user + ).first() + + if share: + share.is_visible = not share.is_visible + share.save() + is_visible = share.is_visible + elif calendar.owner == request.user: + calendar.is_visible = not calendar.is_visible + calendar.save() + is_visible = calendar.is_visible + else: + return drf_response.Response( + {"error": "Permission denied"}, status=status.HTTP_403_FORBIDDEN + ) + + return drf_response.Response({"is_visible": is_visible}) + + @action( + detail=True, + methods=["post"], + serializer_class=serializers.CalendarShareSerializer, + ) + def share(self, request, pk=None): + """Share calendar with another user.""" + calendar = self.get_object() + + if calendar.owner != request.user: + return drf_response.Response( + {"error": "Only the owner can share this calendar"}, + status=status.HTTP_403_FORBIDDEN, + ) + + serializer = serializers.CalendarShareSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + email = serializer.validated_data["shared_with_email"] + try: + user_to_share = models.User.objects.get(email=email) + except models.User.DoesNotExist: + return drf_response.Response( + {"error": "User not found"}, status=status.HTTP_404_NOT_FOUND + ) + + share, created = models.CalendarShare.objects.get_or_create( + calendar=calendar, + shared_with=user_to_share, + defaults={ + "permission": serializer.validated_data.get("permission", "read") + }, + ) + + if not created: + share.permission = serializer.validated_data.get( + "permission", share.permission + ) + share.save() + + return drf_response.Response( + serializers.CalendarShareSerializer(share).data, + status=status.HTTP_201_CREATED if created else status.HTTP_200_OK, + ) diff --git a/src/backend/core/api/viewsets_caldav.py b/src/backend/core/api/viewsets_caldav.py new file mode 100644 index 0000000..710b4df --- /dev/null +++ b/src/backend/core/api/viewsets_caldav.py @@ -0,0 +1,220 @@ +"""CalDAV proxy views for forwarding requests to DAViCal.""" + +import logging + +from django.conf import settings +from django.http import HttpResponse +from django.utils.decorators import method_decorator +from django.views import View +from django.views.decorators.csrf import csrf_exempt + +import requests + +from core.services.caldav_service import DAViCalClient + +logger = logging.getLogger(__name__) + + +@method_decorator(csrf_exempt, name="dispatch") +class CalDAVProxyView(View): + """ + Proxy view that forwards all CalDAV requests to DAViCal. + Handles authentication and adds appropriate headers. + + CSRF protection is disabled because CalDAV uses non-standard HTTP methods + (PROPFIND, REPORT, etc.) that don't work with Django's CSRF middleware. + Authentication is handled via session cookies instead. + """ + + def dispatch(self, request, *args, **kwargs): + """Forward all HTTP methods to DAViCal.""" + # Handle CORS preflight requests + if request.method == "OPTIONS": + response = HttpResponse(status=200) + response["Access-Control-Allow-Methods"] = ( + "GET, OPTIONS, PROPFIND, REPORT, MKCOL, MKCALENDAR, PUT, DELETE" + ) + response["Access-Control-Allow-Headers"] = ( + "Content-Type, depth, authorization, if-match, if-none-match, prefer" + ) + return response + + if not request.user.is_authenticated: + return HttpResponse(status=401) + + # Ensure user exists in DAViCal before making requests + try: + davical_client = DAViCalClient() + davical_client.ensure_user_exists(request.user) + except Exception as e: + logger.warning("Failed to ensure user exists in DAViCal: %s", str(e)) + # Continue anyway - user might already exist + + # Build the DAViCal URL + davical_url = getattr(settings, "DAVICAL_URL", "http://davical:80") + path = kwargs.get("path", "") + + # Use user email as the principal (DAViCal uses email as username) + user_principal = request.user.email + + # Handle root CalDAV requests - return principal collection + if not path or path == user_principal: + # For PROPFIND on root, return the user's principal collection + if request.method == "PROPFIND": + # Get the request path to match the href in response + request_path = request.path + if not request_path.endswith("/"): + request_path += "/" + + # Return multistatus with href matching request URL and calendar-home-set + multistatus = f""" + + + {request_path} + + + {user_principal} + + /api/v1.0/caldav/{user_principal}/ + + + HTTP/1.1 200 OK + + +""" + response = HttpResponse( + content=multistatus, + status=207, + content_type="application/xml; charset=utf-8", + ) + return response + + # For other methods, redirect to principal URL + target_url = f"{davical_url}/caldav.php/{user_principal}/" + else: + # Build target URL with path + # Remove leading slash if present + clean_path = path.lstrip("/") + if clean_path.startswith(user_principal): + # Path already includes principal + target_url = f"{davical_url}/caldav.php/{clean_path}" + else: + # Path is relative to principal + target_url = f"{davical_url}/caldav.php/{user_principal}/{clean_path}" + + # Prepare headers for DAViCal + # Set headers to tell DAViCal it's behind a proxy so it generates correct URLs + script_name = "/api/v1.0/caldav" + headers = { + "Content-Type": request.content_type or "application/xml", + "X-Forwarded-User": user_principal, + "X-Forwarded-For": request.META.get("REMOTE_ADDR", ""), + "X-Forwarded-Prefix": script_name, + "X-Forwarded-Host": request.get_host(), + "X-Forwarded-Proto": request.scheme, + "X-Script-Name": script_name, # Tell DAViCal the base path + } + + # DAViCal authentication: users with password '*' use external auth + # We send the username via X-Forwarded-User header + # For HTTP Basic Auth, we use the email as username with empty password + # This works with DAViCal's external authentication when trust_x_forwarded is true + auth = (user_principal, "") + + # Copy relevant headers from the original request + if "HTTP_DEPTH" in request.META: + headers["Depth"] = request.META["HTTP_DEPTH"] + if "HTTP_IF_MATCH" in request.META: + headers["If-Match"] = request.META["HTTP_IF_MATCH"] + if "HTTP_IF_NONE_MATCH" in request.META: + headers["If-None-Match"] = request.META["HTTP_IF_NONE_MATCH"] + if "HTTP_PREFER" in request.META: + headers["Prefer"] = request.META["HTTP_PREFER"] + + # Get request body + body = request.body if request.body else None + + try: + # Forward the request to DAViCal + # Use HTTP Basic Auth with username (email) and empty password + # DAViCal will authenticate based on X-Forwarded-User header when trust_x_forwarded is true + logger.debug( + "Forwarding %s request to DAViCal: %s (user: %s)", + request.method, + target_url, + user_principal, + ) + response = requests.request( + method=request.method, + url=target_url, + headers=headers, + data=body, + auth=auth, + timeout=30, + allow_redirects=False, + ) + + # Log authentication failures for debugging + if response.status_code == 401: + logger.warning( + "DAViCal returned 401 for user %s at %s. Headers sent: %s", + user_principal, + target_url, + headers, + ) + + # Build Django response + django_response = HttpResponse( + content=response.content, + status=response.status_code, + content_type=response.headers.get("Content-Type", "application/xml"), + ) + + # Copy relevant headers from DAViCal response + for header in ["ETag", "DAV", "Allow", "Location"]: + if header in response.headers: + django_response[header] = response.headers[header] + + return django_response + + except requests.exceptions.RequestException as e: + logger.error("DAViCal proxy error: %s", str(e)) + return HttpResponse( + content=f"CalDAV server error: {str(e)}", + status=502, + content_type="text/plain", + ) + + +@method_decorator(csrf_exempt, name="dispatch") +class CalDAVDiscoveryView(View): + """ + Handle CalDAV discovery requests (well-known URLs). + + Per RFC 6764, this endpoint should redirect to the CalDAV server base URL, + not to a user-specific principal. Clients will then perform PROPFIND on + the base URL to discover their principal. + + CSRF protection is disabled because CalDAV uses non-standard HTTP methods + and this endpoint should be accessible without authentication. + """ + + def dispatch(self, request, *args, **kwargs): + """Handle discovery requests.""" + # Handle CORS preflight requests + if request.method == "OPTIONS": + response = HttpResponse(status=200) + response["Access-Control-Allow-Methods"] = "GET, OPTIONS, PROPFIND" + response["Access-Control-Allow-Headers"] = ( + "Content-Type, depth, authorization" + ) + return response + + # Note: Authentication is not required for discovery per RFC 6764 + # Clients need to discover the CalDAV URL before authenticating + + # Return redirect to CalDAV server base URL + caldav_base_url = f"/api/v1.0/caldav/" + response = HttpResponse(status=301) + response["Location"] = caldav_base_url + return response diff --git a/src/backend/core/apps.py b/src/backend/core/apps.py new file mode 100644 index 0000000..121bcb2 --- /dev/null +++ b/src/backend/core/apps.py @@ -0,0 +1,19 @@ +"""Calendars Core application""" + +from django.apps import AppConfig +from django.utils.translation import gettext_lazy as _ + + +class CoreConfig(AppConfig): + """Configuration class for the calendars core app.""" + + name = "core" + app_label = "core" + verbose_name = _("calendars core application") + + def ready(self): + """ + Import signals when the app is ready. + """ + # pylint: disable=import-outside-toplevel, unused-import + from . import signals # noqa: PLC0415 diff --git a/src/backend/core/authentication/__init__.py b/src/backend/core/authentication/__init__.py new file mode 100644 index 0000000..bcd07f1 --- /dev/null +++ b/src/backend/core/authentication/__init__.py @@ -0,0 +1,52 @@ +"""Custom authentication classes for the calendars core app""" + +from django.conf import settings + +from rest_framework.authentication import BaseAuthentication +from rest_framework.exceptions import AuthenticationFailed + + +class ServerToServerAuthentication(BaseAuthentication): + """ + Custom authentication class for server-to-server requests. + Validates the presence and correctness of the Authorization header. + """ + + AUTH_HEADER = "Authorization" + TOKEN_TYPE = "Bearer" # noqa S105 + + def authenticate(self, request): + """ + Authenticate the server-to-server request by validating the Authorization header. + + This method checks if the Authorization header is present in the request, ensures it + contains a valid token with the correct format, and verifies the token against the + list of allowed server-to-server tokens. If the header is missing, improperly formatted, + or contains an invalid token, an AuthenticationFailed exception is raised. + + Returns: + None: If authentication is successful + (no user is authenticated for server-to-server requests). + + Raises: + AuthenticationFailed: If the Authorization header is missing, malformed, + or contains an invalid token. + """ + auth_header = request.headers.get(self.AUTH_HEADER) + if not auth_header: + raise AuthenticationFailed("Authorization header is missing.") + + # Validate token format and existence + auth_parts = auth_header.split(" ") + if len(auth_parts) != 2 or auth_parts[0] != self.TOKEN_TYPE: + raise AuthenticationFailed("Invalid authorization header.") + + token = auth_parts[1] + if token not in settings.SERVER_TO_SERVER_API_TOKENS: + raise AuthenticationFailed("Invalid server-to-server token.") + + # Authentication is successful, but no user is authenticated + + def authenticate_header(self, request): + """Return the WWW-Authenticate header value.""" + return f"{self.TOKEN_TYPE} realm='Create item server to server'" diff --git a/src/backend/core/authentication/backends.py b/src/backend/core/authentication/backends.py new file mode 100644 index 0000000..5c38894 --- /dev/null +++ b/src/backend/core/authentication/backends.py @@ -0,0 +1,54 @@ +"""Authentication Backends for the Calendars core app.""" + +import logging + +from django.conf import settings +from django.core.exceptions import SuspiciousOperation +from django.utils.translation import gettext_lazy as _ + +from lasuite.oidc_login.backends import ( + OIDCAuthenticationBackend as LaSuiteOIDCAuthenticationBackend, +) + +from core.authentication.exceptions import UserCannotAccessApp +from core.models import DuplicateEmailError + +logger = logging.getLogger(__name__) + + +class OIDCAuthenticationBackend(LaSuiteOIDCAuthenticationBackend): + """Custom OpenID Connect (OIDC) Authentication Backend. + + This class overrides the default OIDC Authentication Backend to accommodate differences + in the User and Identity models, and handles signed and/or encrypted UserInfo response. + """ + + def get_extra_claims(self, user_info): + """ + Return extra claims from user_info. + + Args: + user_info (dict): The user information dictionary. + + Returns: + dict: A dictionary of extra claims. + """ + + # We need to add the claims that we want to store so that they are + # available in the post_get_or_create_user method. + claims_to_store = { + claim: user_info.get(claim) for claim in settings.OIDC_STORE_CLAIMS + } + return { + "full_name": self.compute_full_name(user_info), + "short_name": user_info.get(settings.OIDC_USERINFO_SHORTNAME_FIELD), + "claims": claims_to_store, + } + + def get_existing_user(self, sub, email): + """Fetch existing user by sub or email.""" + + try: + return self.UserModel.objects.get_user_by_sub_or_email(sub, email) + except DuplicateEmailError as err: + raise SuspiciousOperation(err.message) from err diff --git a/src/backend/core/authentication/exceptions.py b/src/backend/core/authentication/exceptions.py new file mode 100644 index 0000000..c1c40cb --- /dev/null +++ b/src/backend/core/authentication/exceptions.py @@ -0,0 +1,5 @@ +"""Exceptions for the authentication module.""" + + +class UserCannotAccessApp(Exception): + """Exception raised when a user cannot access the app.""" diff --git a/src/backend/core/authentication/views.py b/src/backend/core/authentication/views.py new file mode 100644 index 0000000..96e4ad4 --- /dev/null +++ b/src/backend/core/authentication/views.py @@ -0,0 +1,25 @@ +"""Calendars core authentication views.""" + +from django.http import HttpResponseRedirect + +from lasuite.oidc_login.views import ( + OIDCAuthenticationCallbackView as LaSuiteOIDCAuthenticationCallbackView, +) + +from core.authentication.exceptions import UserCannotAccessApp + + +class OIDCAuthenticationCallbackView(LaSuiteOIDCAuthenticationCallbackView): + """ + Custom view for handling the authentication callback from the OpenID Connect (OIDC) provider. + Handles the callback after authentication from the identity provider (OP). + Verifies the state parameter and performs necessary authentication actions. + """ + + def get(self, request): + try: + return super().get(request) + except UserCannotAccessApp: + return HttpResponseRedirect( + self.failure_url + "?auth_error=user_cannot_access_app" + ) diff --git a/src/backend/core/enums.py b/src/backend/core/enums.py new file mode 100644 index 0000000..8f7e70c --- /dev/null +++ b/src/backend/core/enums.py @@ -0,0 +1,12 @@ +""" +Core application enums declaration +""" + +from django.conf import global_settings +from django.utils.translation import gettext_lazy as _ + +# In Django's code base, `LANGUAGES` is set by default with all supported languages. +# We can use it for the choice of languages which should not be limited to the few languages +# active in the app. +# pylint: disable=no-member +ALL_LANGUAGES = {language: _(name) for language, name in global_settings.LANGUAGES} diff --git a/src/backend/core/external_api/permissions.py b/src/backend/core/external_api/permissions.py new file mode 100644 index 0000000..6462e52 --- /dev/null +++ b/src/backend/core/external_api/permissions.py @@ -0,0 +1,41 @@ +"""Resource Server Permissions for the Calendars app.""" + +from django.conf import settings + +from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication +from rest_framework import permissions + + +class ResourceServerClientPermission(permissions.BasePermission): + """ + Permission class for resource server views. + This provides a way to open the resource server views to a limited set of + Service Providers. + Note: we might add a more complex permission system in the future, based on + the Service Provider ID and the requested scopes. + """ + + def has_permission(self, request, view): + """ + Check if the user is authenticated and the token introspection + provides an authorized Service Provider. + """ + if not isinstance( + request.successful_authenticator, ResourceServerAuthentication + ): + # Not a resource server request + return False + + # Check if the user is authenticated + if not request.user.is_authenticated: + return False + if ( + hasattr(view, "resource_server_actions") + and view.action not in view.resource_server_actions + ): + return False + + # When used as a resource server, the request has a token audience + return ( + request.resource_server_token_audience in settings.OIDC_RS_ALLOWED_AUDIENCES + ) diff --git a/src/backend/core/external_api/viewsets.py b/src/backend/core/external_api/viewsets.py new file mode 100644 index 0000000..1d6e4c7 --- /dev/null +++ b/src/backend/core/external_api/viewsets.py @@ -0,0 +1,36 @@ +"""Resource Server Viewsets for the Calendars app.""" + +from django.conf import settings + +from lasuite.oidc_resource_server.authentication import ResourceServerAuthentication + +from core.api.permissions import AccessPermission, IsSelf +from core.api.viewsets import UserViewSet +from core.external_api.permissions import ResourceServerClientPermission + +# pylint: disable=too-many-ancestors + + +class ResourceServerRestrictionMixin: + """ + Mixin for Resource Server Viewsets to provide shortcut to get + configured actions for a given resource. + """ + + def _get_resource_server_actions(self, resource_name): + """Get resource_server_actions from settings.""" + external_api_config = settings.EXTERNAL_API.get(resource_name, {}) + return list(external_api_config.get("actions", [])) + + +class ResourceServerUserViewSet(ResourceServerRestrictionMixin, UserViewSet): + """Resource Server Viewset for the Calendars app.""" + + authentication_classes = [ResourceServerAuthentication] + + permission_classes = [ResourceServerClientPermission & IsSelf] + + @property + def resource_server_actions(self): + """Get resource_server_actions from settings.""" + return self._get_resource_server_actions("users") diff --git a/src/backend/core/factories.py b/src/backend/core/factories.py new file mode 100644 index 0000000..8b9a0f7 --- /dev/null +++ b/src/backend/core/factories.py @@ -0,0 +1,28 @@ +""" +Core application factories +""" + +from django.conf import settings +from django.contrib.auth.hashers import make_password + +import factory.fuzzy +from faker import Faker + +from core import models + +fake = Faker() + + +class UserFactory(factory.django.DjangoModelFactory): + """A factory to random users for testing purposes.""" + + class Meta: + model = models.User + skip_postgeneration_save = True + + sub = factory.Sequence(lambda n: f"user{n!s}") + email = factory.Faker("email") + full_name = factory.Faker("name") + short_name = factory.Faker("first_name") + language = factory.fuzzy.FuzzyChoice([lang[0] for lang in settings.LANGUAGES]) + password = make_password("password") diff --git a/src/backend/core/management/commands/__init__.py b/src/backend/core/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/management/commands/createsuperuser.py b/src/backend/core/management/commands/createsuperuser.py new file mode 100644 index 0000000..e45649e --- /dev/null +++ b/src/backend/core/management/commands/createsuperuser.py @@ -0,0 +1,47 @@ +"""Management user to create a superuser.""" + +from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand + +UserModel = get_user_model() + + +class Command(BaseCommand): + """Management command to create a superuser from an email and password.""" + + help = "Create a superuser with an email and a password" + + def add_arguments(self, parser): + """Define required arguments "email" and "password".""" + parser.add_argument( + "--email", + help=("Email for the user."), + ) + parser.add_argument( + "--password", + help="Password for the user.", + ) + + def handle(self, *args, **options): + """ + Given an email and a password, create a superuser or upgrade the existing + user to superuser status. + """ + email = options.get("email") + try: + user = UserModel.objects.get(admin_email=email) + except UserModel.DoesNotExist: + user = UserModel(admin_email=email) + message = "Superuser created successfully." + else: + if user.is_superuser and user.is_staff: + message = "Superuser already exists." + else: + message = "User already existed and was upgraded to superuser." + + user.is_superuser = True + user.is_staff = True + user.set_password(options["password"]) + user.save() + + self.stdout.write(self.style.SUCCESS(message)) diff --git a/src/backend/core/migrations/0001_initial.py b/src/backend/core/migrations/0001_initial.py new file mode 100644 index 0000000..f22e6ea --- /dev/null +++ b/src/backend/core/migrations/0001_initial.py @@ -0,0 +1,90 @@ +# Generated by Django 5.2.9 on 2026-01-08 23:49 + +import core.models +import django.core.validators +import django.db.models.deletion +import timezone_field.fields +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='User', + fields=[ + ('password', models.CharField(max_length=128, verbose_name='password')), + ('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')), + ('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')), + ('id', models.UUIDField(default=uuid.uuid4, editable=False, help_text='primary key for the record as UUID', primary_key=True, serialize=False, verbose_name='id')), + ('created_at', models.DateTimeField(auto_now_add=True, help_text='date and time at which a record was created', verbose_name='created on')), + ('updated_at', models.DateTimeField(auto_now=True, help_text='date and time at which a record was last updated', verbose_name='updated on')), + ('sub', models.CharField(blank=True, help_text='Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only.', max_length=255, null=True, unique=True, validators=[django.core.validators.RegexValidator(message='Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/_/: characters.', regex='^[\\w.@+-:]+\\Z')], verbose_name='sub')), + ('full_name', models.CharField(blank=True, max_length=100, null=True, verbose_name='full name')), + ('short_name', models.CharField(blank=True, max_length=20, null=True, verbose_name='short name')), + ('email', models.EmailField(blank=True, max_length=254, null=True, verbose_name='identity email address')), + ('admin_email', models.EmailField(blank=True, max_length=254, null=True, unique=True, verbose_name='admin email address')), + ('language', models.CharField(blank=True, choices=[('en-us', 'English'), ('fr-fr', 'French'), ('de-de', 'German'), ('nl-nl', 'Dutch')], default=None, help_text='The language in which the user wants to see the interface.', max_length=10, null=True, verbose_name='language')), + ('timezone', timezone_field.fields.TimeZoneField(choices_display='WITH_GMT_OFFSET', default='UTC', help_text='The timezone in which the user wants to see times.', use_pytz=False)), + ('is_device', models.BooleanField(default=False, help_text='Whether the user is a device or a real user.', verbose_name='device')), + ('is_staff', models.BooleanField(default=False, help_text='Whether the user can log into this admin site.', verbose_name='staff status')), + ('is_active', models.BooleanField(default=True, help_text='Whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')), + ('claims', models.JSONField(blank=True, default=dict, help_text='Claims from the OIDC token.')), + ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.group', verbose_name='groups')), + ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.permission', verbose_name='user permissions')), + ], + options={ + 'verbose_name': 'user', + 'verbose_name_plural': 'users', + 'db_table': 'calendars_user', + }, + managers=[ + ('objects', core.models.UserManager()), + ], + ), + migrations.CreateModel( + name='Calendar', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('name', models.CharField(max_length=255)), + ('color', models.CharField(default='#3174ad', max_length=7)), + ('description', models.TextField(blank=True, default='')), + ('is_default', models.BooleanField(default=False)), + ('is_visible', models.BooleanField(default=True)), + ('davical_path', models.CharField(max_length=512, unique=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('owner', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='calendars', to=settings.AUTH_USER_MODEL)), + ], + options={ + 'ordering': ['-is_default', 'name'], + }, + ), + migrations.CreateModel( + name='CalendarShare', + fields=[ + ('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)), + ('permission', models.CharField(choices=[('read', 'Read only'), ('write', 'Read and write')], default='read', max_length=10)), + ('is_visible', models.BooleanField(default=True)), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('calendar', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shares', to='core.calendar')), + ('shared_with', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='shared_calendars', to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.AddConstraint( + model_name='calendar', + constraint=models.UniqueConstraint(condition=models.Q(('is_default', True)), fields=('owner',), name='unique_default_calendar_per_user'), + ), + migrations.AlterUniqueTogether( + name='calendarshare', + unique_together={('calendar', 'shared_with')}, + ), + ] diff --git a/src/backend/core/migrations/__init__.py b/src/backend/core/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/models.py b/src/backend/core/models.py new file mode 100644 index 0000000..3fc9df1 --- /dev/null +++ b/src/backend/core/models.py @@ -0,0 +1,402 @@ +""" +Declare and configure the models for the calendars core application +""" +# pylint: disable=too-many-lines + +import uuid +from datetime import timedelta +from logging import getLogger + +from django.conf import settings +from django.contrib.auth import models as auth_models +from django.contrib.auth.base_user import AbstractBaseUser +from django.contrib.postgres.indexes import GistIndex +from django.contrib.sites.models import Site +from django.core import mail, validators +from django.core.cache import cache +from django.core.exceptions import ValidationError +from django.core.mail import send_mail +from django.db import models, transaction +from django.db.models.expressions import RawSQL +from django.template.loader import render_to_string +from django.utils import timezone +from django.utils.functional import cached_property +from django.utils.translation import get_language, override +from django.utils.translation import gettext_lazy as _ + +from timezone_field import TimeZoneField + +logger = getLogger(__name__) + + +class LinkRoleChoices(models.TextChoices): + """Defines the possible roles a link can offer on a item.""" + + READER = "reader", _("Reader") # Can read + EDITOR = "editor", _("Editor") # Can read and edit + + +class RoleChoices(models.TextChoices): + """Defines the possible roles a user can have in a resource.""" + + READER = "reader", _("Reader") # Can read + EDITOR = "editor", _("Editor") # Can read and edit + ADMIN = "administrator", _("Administrator") # Can read, edit, delete and share + OWNER = "owner", _("Owner") + + +PRIVILEGED_ROLES = [RoleChoices.ADMIN, RoleChoices.OWNER] + + +class LinkReachChoices(models.TextChoices): + """Defines types of access for links""" + + RESTRICTED = ( + "restricted", + _("Restricted"), + ) # Only users with a specific access can read/edit the item + AUTHENTICATED = ( + "authenticated", + _("Authenticated"), + ) # Any authenticated user can access the item + PUBLIC = "public", _("Public") # Even anonymous users can access the item + + +class DuplicateEmailError(Exception): + """Raised when an email is already associated with a pre-existing user.""" + + def __init__(self, message=None, email=None): + """Set message and email to describe the exception.""" + self.message = message + self.email = email + super().__init__(self.message) + + +class BaseModel(models.Model): + """ + Serves as an abstract base model for other models, ensuring that records are validated + before saving as Django doesn't do it by default. + + Includes fields common to all models: a UUID primary key and creation/update timestamps. + """ + + id = models.UUIDField( + verbose_name=_("id"), + help_text=_("primary key for the record as UUID"), + primary_key=True, + default=uuid.uuid4, + editable=False, + ) + created_at = models.DateTimeField( + verbose_name=_("created on"), + help_text=_("date and time at which a record was created"), + auto_now_add=True, + editable=False, + ) + updated_at = models.DateTimeField( + verbose_name=_("updated on"), + help_text=_("date and time at which a record was last updated"), + auto_now=True, + editable=False, + ) + + class Meta: + abstract = True + + def save(self, *args, **kwargs): + """Call `full_clean` before saving.""" + self.full_clean() + super().save(*args, **kwargs) + + +class UserManager(auth_models.UserManager): + """Custom manager for User model with additional methods.""" + + def get_user_by_sub_or_email(self, sub, email): + """Fetch existing user by sub or email.""" + try: + return self.get(sub=sub) + except self.model.DoesNotExist as err: + if not email: + return None + + if settings.OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION: + try: + return self.get(email=email) + except self.model.DoesNotExist: + pass + elif ( + self.filter(email=email).exists() + and not settings.OIDC_ALLOW_DUPLICATE_EMAILS + ): + raise DuplicateEmailError( + _( + "We couldn't find a user with this sub but the email is already " + "associated with a registered user." + ) + ) from err + return None + + +class User(AbstractBaseUser, BaseModel, auth_models.PermissionsMixin): + """User model to work with OIDC only authentication.""" + + sub_validator = validators.RegexValidator( + regex=r"^[\w.@+-:]+\Z", + message=_( + "Enter a valid sub. This value may contain only letters, " + "numbers, and @/./+/-/_/: characters." + ), + ) + + sub = models.CharField( + _("sub"), + help_text=_( + "Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: characters only." + ), + max_length=255, + unique=True, + validators=[sub_validator], + blank=True, + null=True, + ) + + full_name = models.CharField(_("full name"), max_length=100, null=True, blank=True) + short_name = models.CharField(_("short name"), max_length=20, null=True, blank=True) + + email = models.EmailField(_("identity email address"), blank=True, null=True) + + # Unlike the "email" field which stores the email coming from the OIDC token, this field + # stores the email used by staff users to login to the admin site + admin_email = models.EmailField( + _("admin email address"), unique=True, blank=True, null=True + ) + + language = models.CharField( + max_length=10, + choices=settings.LANGUAGES, + default=None, + verbose_name=_("language"), + help_text=_("The language in which the user wants to see the interface."), + null=True, + blank=True, + ) + timezone = TimeZoneField( + choices_display="WITH_GMT_OFFSET", + use_pytz=False, + default=settings.TIME_ZONE, + help_text=_("The timezone in which the user wants to see times."), + ) + is_device = models.BooleanField( + _("device"), + default=False, + help_text=_("Whether the user is a device or a real user."), + ) + is_staff = models.BooleanField( + _("staff status"), + default=False, + help_text=_("Whether the user can log into this admin site."), + ) + is_active = models.BooleanField( + _("active"), + default=True, + help_text=_( + "Whether this user should be treated as active. " + "Unselect this instead of deleting accounts." + ), + ) + + claims = models.JSONField( + blank=True, + default=dict, + help_text=_("Claims from the OIDC token."), + ) + + objects = UserManager() + + USERNAME_FIELD = "admin_email" + REQUIRED_FIELDS = [] + + class Meta: + db_table = "calendars_user" + verbose_name = _("user") + verbose_name_plural = _("users") + + def __str__(self): + return self.email or self.admin_email or str(self.id) + + def save(self, *args, **kwargs): + """ + If it's a new user, give its user access to the items to which s.he was invited. + """ + is_adding = self._state.adding + + super().save(*args, **kwargs) + + def email_user(self, subject, message, from_email=None, **kwargs): + """Email this user.""" + if not self.email: + raise ValueError("User has no email address.") + mail.send_mail(subject, message, from_email, [self.email], **kwargs) + + @cached_property + def teams(self): + """ + Get list of teams in which the user is, as a list of strings. + Must be cached if retrieved remotely. + """ + return [] + + +class BaseAccess(BaseModel): + """Base model for accesses to handle resources.""" + + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + null=True, + blank=True, + ) + team = models.CharField(max_length=100, blank=True) + role = models.CharField( + max_length=20, choices=RoleChoices.choices, default=RoleChoices.READER + ) + + class Meta: + abstract = True + + def _get_abilities(self, resource, user): + """ + Compute and return abilities for a given user taking into account + the current state of the object. + """ + roles = [] + if user.is_authenticated: + teams = user.teams + try: + roles = self.user_roles or [] + except AttributeError: + try: + roles = resource.accesses.filter( + models.Q(user=user) | models.Q(team__in=teams), + ).values_list("role", flat=True) + except (self._meta.model.DoesNotExist, IndexError): + roles = [] + + is_owner_or_admin = bool( + set(roles).intersection({RoleChoices.OWNER, RoleChoices.ADMIN}) + ) + if self.role == RoleChoices.OWNER: + can_delete = ( + RoleChoices.OWNER in roles + and resource.accesses.filter(role=RoleChoices.OWNER).count() > 1 + ) + set_role_to = ( + [RoleChoices.ADMIN, RoleChoices.EDITOR, RoleChoices.READER] + if can_delete + else [] + ) + else: + can_delete = is_owner_or_admin + set_role_to = [] + if RoleChoices.OWNER in roles: + set_role_to.append(RoleChoices.OWNER) + if is_owner_or_admin: + set_role_to.extend( + [RoleChoices.ADMIN, RoleChoices.EDITOR, RoleChoices.READER] + ) + + # Remove the current role as we don't want to propose it as an option + try: + set_role_to.remove(self.role) + except ValueError: + pass + + return { + "destroy": can_delete, + "update": bool(set_role_to), + "partial_update": bool(set_role_to), + "retrieve": bool(roles), + "set_role_to": set_role_to, + } + + +class Calendar(models.Model): + """ + Represents a calendar owned by a user. + This model tracks calendars stored in DAViCal and links them to Django users. + """ + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + owner = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + related_name="calendars", + ) + name = models.CharField(max_length=255) + color = models.CharField(max_length=7, default="#3174ad") # Hex color + description = models.TextField(blank=True, default="") + is_default = models.BooleanField(default=False) + is_visible = models.BooleanField(default=True) + + # DAViCal reference - the calendar path in DAViCal + davical_path = models.CharField(max_length=512, unique=True) + + created_at = models.DateTimeField(auto_now_add=True) + updated_at = models.DateTimeField(auto_now=True) + + class Meta: + """Meta options for Calendar model.""" + + ordering = ["-is_default", "name"] + constraints = [ + models.UniqueConstraint( + fields=["owner"], + condition=models.Q(is_default=True), + name="unique_default_calendar_per_user", + ) + ] + + def __str__(self): + return f"{self.name} ({self.owner.email})" + + +class CalendarShare(models.Model): + """ + Represents a calendar shared with another user. + """ + + PERMISSION_READ = "read" + PERMISSION_WRITE = "write" + PERMISSION_CHOICES = [ + (PERMISSION_READ, "Read only"), + (PERMISSION_WRITE, "Read and write"), + ] + + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + calendar = models.ForeignKey( + Calendar, + on_delete=models.CASCADE, + related_name="shares", + ) + shared_with = models.ForeignKey( + settings.AUTH_USER_MODEL, + on_delete=models.CASCADE, + related_name="shared_calendars", + ) + permission = models.CharField( + max_length=10, + choices=PERMISSION_CHOICES, + default=PERMISSION_READ, + ) + is_visible = models.BooleanField(default=True) + + created_at = models.DateTimeField(auto_now_add=True) + + class Meta: + """Meta options for CalendarShare model.""" + + unique_together = ["calendar", "shared_with"] + + def __str__(self): + return f"{self.calendar.name} shared with {self.shared_with.email}" diff --git a/src/backend/core/services/__init__.py b/src/backend/core/services/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/services/caldav_service.py b/src/backend/core/services/caldav_service.py new file mode 100644 index 0000000..405be4b --- /dev/null +++ b/src/backend/core/services/caldav_service.py @@ -0,0 +1,477 @@ +"""Services for CalDAV integration with DAViCal.""" + +import logging +from datetime import date, datetime, timedelta +from typing import Optional +from uuid import uuid4 + +from django.conf import settings +from django.utils import timezone + +import psycopg + +from caldav import DAVClient +from caldav.lib.error import NotFoundError +from core.models import Calendar + +logger = logging.getLogger(__name__) + + +class DAViCalClient: + """ + Client for communicating with DAViCal CalDAV server using the caldav library. + """ + + def __init__(self): + self.base_url = getattr(settings, "DAVICAL_URL", "http://davical:80") + self.timeout = 30 + + def _get_client(self, user) -> DAVClient: + """ + Get a CalDAV client for the given user. + + DAViCal uses X-Forwarded-User header for authentication. The caldav + library requires username/password for Basic Auth, but DAViCal users have + password '*' (external auth). We pass the X-Forwarded-User header directly + to the DAVClient constructor. + """ + # DAViCal base URL - the caldav library will discover the principal + caldav_url = f"{self.base_url}/caldav.php/" + + return DAVClient( + url=caldav_url, + username=user.email, + password="", # Empty password - DAViCal uses X-Forwarded-User header + timeout=self.timeout, + headers={ + "X-Forwarded-User": user.email, + }, + ) + + def ensure_user_exists(self, user) -> None: + """ + Ensure the user exists in DAViCal's database. + Creates the user if they don't exist. + """ + # Connect to shared calendars database (public schema) + default_db = settings.DATABASES["default"] + db_name = default_db.get("NAME", "calendars") + + # Get password - handle SecretValue objects + password = default_db.get("PASSWORD", "pass") + if hasattr(password, "value"): + password = password.value + + # Connect to calendars database + conn = psycopg.connect( + host=default_db.get("HOST", "localhost"), + port=default_db.get("PORT", 5432), + dbname=db_name, + user=default_db.get("USER", "pgroot"), + password=password, + ) + + try: + with conn.cursor() as cursor: + # Check if user exists (in public schema) + cursor.execute( + "SELECT user_no FROM usr WHERE lower(username) = lower(%s)", + [user.email], + ) + if cursor.fetchone(): + # User already exists + return + + # Create user in DAViCal (public schema) + # Use email as username, password '*' means external auth + # Get user's full name or use email prefix + fullname = ( + getattr(user, "full_name", None) + or getattr(user, "get_full_name", lambda: None)() + or user.email.split("@")[0] + ) + + cursor.execute( + """ + INSERT INTO usr (username, email, fullname, active, password) + VALUES (%s, %s, %s, true, '*') + ON CONFLICT (lower(username)) DO NOTHING + RETURNING user_no + """, + [user.email, user.email, fullname], + ) + result = cursor.fetchone() + if result: + user_no = result[0] + logger.info( + "Created DAViCal user: %s (user_no: %s)", user.email, user_no + ) + + # Also create a principal record for the user (public schema) + # DAViCal needs both usr and principal records + # Principal type 1 is for users + type_id = 1 + + cursor.execute( + """ + INSERT INTO principal (type_id, user_no, displayname) + SELECT %s, %s, %s + WHERE NOT EXISTS (SELECT 1 FROM principal WHERE user_no = %s) + RETURNING principal_id + """, + [type_id, user_no, fullname, user_no], + ) + principal_result = cursor.fetchone() + if principal_result: + logger.info( + "Created DAViCal principal: %s (principal_id: %s)", + user.email, + principal_result[0], + ) + else: + logger.warning("User %s already exists in DAViCal", user.email) + conn.commit() + finally: + conn.close() + + def create_calendar(self, user, calendar_name: str, calendar_id: str) -> str: + """ + Create a new calendar in DAViCal for the given user. + Returns the DAViCal path for the calendar. + """ + # Ensure user exists first + self.ensure_user_exists(user) + + client = self._get_client(user) + principal = client.principal() + + try: + # Create calendar using caldav library + calendar = principal.make_calendar(name=calendar_name) + + # DAViCal calendar path format: /caldav.php/{username}/{calendar_id}/ + # The caldav library returns a URL object, convert to string and extract path + calendar_url = str(calendar.url) + # Extract path from full URL + if calendar_url.startswith(self.base_url): + path = calendar_url[len(self.base_url) :] + else: + # Fallback: construct path manually based on DAViCal's structure + # DAViCal creates calendars with a specific path structure + path = f"/caldav.php/{user.email}/{calendar_id}/" + + logger.info("Created calendar in DAViCal: %s at %s", calendar_name, path) + return path + except Exception as e: + logger.error("Failed to create calendar in DAViCal: %s", str(e)) + raise + + def get_events( + self, + user, + calendar_path: str, + start: Optional[datetime] = None, + end: Optional[datetime] = None, + ) -> list: + """ + Get events from a calendar within a time range. + Returns list of event dictionaries with parsed data. + """ + # Ensure user exists first + self.ensure_user_exists(user) + + # Default to current month if no range specified + if start is None: + start = timezone.now().replace(day=1, hour=0, minute=0, second=0) + if end is None: + end = start + timedelta(days=31) + + client = self._get_client(user) + + # Get calendar by URL + calendar_url = f"{self.base_url}{calendar_path}" + calendar = client.calendar(url=calendar_url) + + try: + # Search for events in the date range + # Convert datetime to date for search if needed + start_date = start.date() if isinstance(start, datetime) else start + end_date = end.date() if isinstance(end, datetime) else end + + events = calendar.search( + event=True, + start=start_date, + end=end_date, + expand=True, # Expand recurring events + ) + + # Parse events into dictionaries + parsed_events = [] + for event in events: + event_data = self._parse_event(event) + if event_data: + parsed_events.append(event_data) + + return parsed_events + except NotFoundError: + logger.warning("Calendar not found at path: %s", calendar_path) + return [] + except Exception as e: + logger.error("Failed to get events from DAViCal: %s", str(e)) + raise + + def create_event(self, user, calendar_path: str, event_data: dict) -> str: + """ + Create a new event in DAViCal. + Returns the event UID. + """ + # Ensure user exists first + self.ensure_user_exists(user) + + client = self._get_client(user) + calendar_url = f"{self.base_url}{calendar_path}" + calendar = client.calendar(url=calendar_url) + + # Extract event data + dtstart = event_data.get("start", timezone.now()) + dtend = event_data.get("end", dtstart + timedelta(hours=1)) + summary = event_data.get("title", "New Event") + description = event_data.get("description", "") + location = event_data.get("location", "") + + # Generate UID if not provided + event_uid = event_data.get("uid", str(uuid4())) + + try: + # Create event using caldav library + event = calendar.save_event( + dtstart=dtstart, + dtend=dtend, + uid=event_uid, + summary=summary, + description=description, + location=location, + ) + + # Extract UID from created event + # The caldav library returns an Event object + if hasattr(event, "icalendar_component"): + event_uid = str(event.icalendar_component.get("uid", event_uid)) + elif hasattr(event, "vobject_instance"): + event_uid = event.vobject_instance.vevent.uid.value + + logger.info("Created event in DAViCal: %s", event_uid) + return event_uid + except Exception as e: + logger.error("Failed to create event in DAViCal: %s", str(e)) + raise + + def update_event( + self, user, calendar_path: str, event_uid: str, event_data: dict + ) -> None: + """Update an existing event in DAViCal.""" + # Ensure user exists first + self.ensure_user_exists(user) + + client = self._get_client(user) + calendar_url = f"{self.base_url}{calendar_path}" + calendar = client.calendar(url=calendar_url) + + try: + # Search for the event by UID + events = calendar.search(event=True) + target_event = None + + for event in events: + event_uid_value = None + if hasattr(event, "icalendar_component"): + event_uid_value = str(event.icalendar_component.get("uid", "")) + elif hasattr(event, "vobject_instance"): + event_uid_value = event.vobject_instance.vevent.uid.value + + if event_uid_value == event_uid: + target_event = event + break + + if not target_event: + raise ValueError(f"Event with UID {event_uid} not found") + + # Update event properties + dtstart = event_data.get("start") + dtend = event_data.get("end") + summary = event_data.get("title") + description = event_data.get("description") + location = event_data.get("location") + + # Update using icalendar component + component = target_event.icalendar_component + + if dtstart: + component["dtstart"] = dtstart + if dtend: + component["dtend"] = dtend + if summary: + component["summary"] = summary + if description is not None: + component["description"] = description + if location is not None: + component["location"] = location + + # Save the updated event + target_event.save() + + logger.info("Updated event in DAViCal: %s", event_uid) + except Exception as e: + logger.error("Failed to update event in DAViCal: %s", str(e)) + raise + + def delete_event(self, user, calendar_path: str, event_uid: str) -> None: + """Delete an event from DAViCal.""" + # Ensure user exists first + self.ensure_user_exists(user) + + client = self._get_client(user) + calendar_url = f"{self.base_url}{calendar_path}" + calendar = client.calendar(url=calendar_url) + + try: + # Search for the event by UID + events = calendar.search(event=True) + target_event = None + + for event in events: + event_uid_value = None + if hasattr(event, "icalendar_component"): + event_uid_value = str(event.icalendar_component.get("uid", "")) + elif hasattr(event, "vobject_instance"): + event_uid_value = event.vobject_instance.vevent.uid.value + + if event_uid_value == event_uid: + target_event = event + break + + if not target_event: + raise ValueError(f"Event with UID {event_uid} not found") + + # Delete the event + target_event.delete() + + logger.info("Deleted event from DAViCal: %s", event_uid) + except Exception as e: + logger.error("Failed to delete event from DAViCal: %s", str(e)) + raise + + def _parse_event(self, event) -> Optional[dict]: + """ + Parse a caldav Event object and return event data as dictionary. + """ + try: + component = event.icalendar_component + + event_data = { + "uid": str(component.get("uid", "")), + "title": str(component.get("summary", "")), + "start": component.get("dtstart").dt + if component.get("dtstart") + else None, + "end": component.get("dtend").dt if component.get("dtend") else None, + "description": str(component.get("description", "")), + "location": str(component.get("location", "")), + } + + # Convert datetime to string format for consistency + if event_data["start"]: + if isinstance(event_data["start"], datetime): + event_data["start"] = event_data["start"].strftime("%Y%m%dT%H%M%SZ") + elif isinstance(event_data["start"], date): + event_data["start"] = event_data["start"].strftime("%Y%m%d") + + if event_data["end"]: + if isinstance(event_data["end"], datetime): + event_data["end"] = event_data["end"].strftime("%Y%m%dT%H%M%SZ") + elif isinstance(event_data["end"], date): + event_data["end"] = event_data["end"].strftime("%Y%m%d") + + return event_data if event_data.get("uid") else None + except Exception as e: + logger.warning("Failed to parse event: %s", str(e)) + return None + + +class CalendarService: + """ + High-level service for managing calendars and events. + """ + + def __init__(self): + self.davical = DAViCalClient() + + def create_default_calendar(self, user) -> Calendar: + """ + Create a default calendar for a user. + """ + calendar_id = str(uuid4()) + calendar_name = "Mon calendrier" + + # Create calendar in DAViCal + davical_path = self.davical.create_calendar(user, calendar_name, calendar_id) + + # Create local Calendar record + calendar = Calendar.objects.create( + owner=user, + name=calendar_name, + davical_path=davical_path, + is_default=True, + color="#3174ad", + ) + + return calendar + + def create_calendar(self, user, name: str, color: str = "#3174ad") -> Calendar: + """ + Create a new calendar for a user. + """ + calendar_id = str(uuid4()) + + # Create calendar in DAViCal + davical_path = self.davical.create_calendar(user, name, calendar_id) + + # Create local Calendar record + calendar = Calendar.objects.create( + owner=user, + name=name, + davical_path=davical_path, + is_default=False, + color=color, + ) + + return calendar + + def get_user_calendars(self, user): + """ + Get all calendars accessible by a user (owned + shared). + """ + owned = Calendar.objects.filter(owner=user) + shared = Calendar.objects.filter(shares__shared_with=user) + return owned.union(shared) + + def get_events(self, user, calendar: Calendar, start=None, end=None) -> list: + """ + Get events from a calendar. + Returns parsed event data. + """ + return self.davical.get_events(user, calendar.davical_path, start, end) + + def create_event(self, user, calendar: Calendar, event_data: dict) -> str: + """Create a new event.""" + return self.davical.create_event(user, calendar.davical_path, event_data) + + def update_event( + self, user, calendar: Calendar, event_uid: str, event_data: dict + ) -> None: + """Update an existing event.""" + self.davical.update_event(user, calendar.davical_path, event_uid, event_data) + + def delete_event(self, user, calendar: Calendar, event_uid: str) -> None: + """Delete an event.""" + self.davical.delete_event(user, calendar.davical_path, event_uid) diff --git a/src/backend/core/signals.py b/src/backend/core/signals.py new file mode 100644 index 0000000..ee9266c --- /dev/null +++ b/src/backend/core/signals.py @@ -0,0 +1,55 @@ +""" +Declare and configure the signals for the calendars core application +""" + +import logging + +from django.conf import settings +from django.contrib.auth import get_user_model +from django.db.models.signals import post_save +from django.dispatch import receiver + +from core.services.caldav_service import CalendarService + +logger = logging.getLogger(__name__) +User = get_user_model() + + +@receiver(post_save, sender=User) +def provision_default_calendar(sender, instance, created, **kwargs): + """ + Auto-provision a default calendar when a new user is created. + """ + if not created: + return + + # Check if user already has a default calendar + if instance.calendars.filter(is_default=True).exists(): + return + + # Skip calendar creation if DAViCal is not configured + if not getattr(settings, "DAVICAL_URL", None): + return + + try: + service = CalendarService() + service.create_default_calendar(instance) + logger.info("Created default calendar for user %s", instance.email) + except Exception as e: + # In tests, DAViCal tables don't exist, so fail silently + # Check if it's a database error that suggests we're in tests + error_str = str(e).lower() + if "does not exist" in error_str or "relation" in error_str: + # Likely in test environment, fail silently + logger.debug( + "Skipped calendar creation for user %s (likely test environment): %s", + instance.email, + str(e), + ) + else: + # Real error, log it + logger.error( + "Failed to create default calendar for user %s: %s", + instance.email, + str(e), + ) diff --git a/src/backend/core/templatetags/__init__.py b/src/backend/core/templatetags/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/templatetags/extra_tags.py b/src/backend/core/templatetags/extra_tags.py new file mode 100644 index 0000000..37ab50b --- /dev/null +++ b/src/backend/core/templatetags/extra_tags.py @@ -0,0 +1,58 @@ +"""Custom template tags for the calendars core application.""" + +import base64 + +from django import template +from django.contrib.staticfiles import finders + +from PIL import ImageFile as PillowImageFile + +register = template.Library() + + +def image_to_base64(file_or_path, close=False): + """ + Return the src string of the base64 encoding of an image represented by its path + or file opened or not. + + Inspired by Django's "get_image_dimensions" + """ + pil_parser = PillowImageFile.Parser() + if hasattr(file_or_path, "read"): + file = file_or_path + if file.closed and hasattr(file, "open"): + file_or_path.open() + file_pos = file.tell() + file.seek(0) + else: + try: + # pylint: disable=consider-using-with + file = open(file_or_path, "rb") + except OSError: + return "" + close = True + + try: + image_data = file.read() + if not image_data: + return "" + pil_parser.feed(image_data) + if pil_parser.image: + mime_type = pil_parser.image.get_format_mimetype() + encoded_string = base64.b64encode(image_data) + return f"data:{mime_type:s};base64, {encoded_string.decode('utf-8'):s}" + return "" + finally: + if close: + file.close() + else: + file.seek(file_pos) + + +@register.simple_tag +def base64_static(path): + """Return a static file into a base64.""" + full_path = finders.find(path) + if full_path: + return image_to_base64(full_path, True) + return "" diff --git a/src/backend/core/tests/__init__.py b/src/backend/core/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/tests/authentication/__init__.py b/src/backend/core/tests/authentication/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/tests/authentication/test_backends.py b/src/backend/core/tests/authentication/test_backends.py new file mode 100644 index 0000000..1bda314 --- /dev/null +++ b/src/backend/core/tests/authentication/test_backends.py @@ -0,0 +1,579 @@ +"""Unit tests for the Authentication Backends.""" + +import random +import re +from unittest import mock + +from django.core.exceptions import SuspiciousOperation +from django.test.utils import override_settings + +import pytest +import responses +from cryptography.fernet import Fernet +from lasuite.oidc_login.backends import get_oidc_refresh_token + +from core import models +from core.authentication.backends import OIDCAuthenticationBackend +from core.authentication.exceptions import UserCannotAccessApp +from core.factories import UserFactory + +pytestmark = pytest.mark.django_db + + +def test_authentication_getter_existing_user_no_email( + django_assert_num_queries, monkeypatch +): + """ + If an existing user matches the user's info sub, the user should be returned. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory() + + def get_userinfo_mocked(*args): + return {"sub": db_user.sub} + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + with django_assert_num_queries(1): + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user == db_user + + +def test_authentication_getter_existing_user_via_email( + django_assert_num_queries, monkeypatch +): + """ + If an existing user doesn't match the sub but matches the email, + the user should be returned. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory() + + def get_userinfo_mocked(*args): + return {"sub": "123", "email": db_user.email} + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + with django_assert_num_queries(4): # user by sub, user by mail, update sub + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user == db_user + + +def test_authentication_getter_email_none(monkeypatch): + """ + If no user is found with the sub and no email is provided, a new user should be created. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory(email=None) + + def get_userinfo_mocked(*args): + user_info = {"sub": "123"} + if random.choice([True, False]): + user_info["email"] = None + return user_info + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + # Since the sub and email didn't match, it should create a new user + assert models.User.objects.count() == 2 + assert user != db_user + assert user.sub == "123" + + +def test_authentication_getter_existing_user_no_fallback_to_email_allow_duplicate( + settings, monkeypatch +): + """ + When the "OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION" setting is set to False, + the system should not match users by email, even if the email matches. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory() + + # Set the setting to False + settings.OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION = False + settings.OIDC_ALLOW_DUPLICATE_EMAILS = True + + def get_userinfo_mocked(*args): + return {"sub": "123", "email": db_user.email} + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + # Since the sub doesn't match, it should create a new user + assert models.User.objects.count() == 2 + assert user != db_user + assert user.sub == "123" + + +def test_authentication_getter_existing_user_no_fallback_to_email_no_duplicate( + settings, monkeypatch +): + """ + When the "OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION" setting is set to False, + the system should not match users by email, even if the email matches. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory() + + # Set the setting to False + settings.OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION = False + settings.OIDC_ALLOW_DUPLICATE_EMAILS = False + + def get_userinfo_mocked(*args): + return {"sub": "123", "email": db_user.email} + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + with pytest.raises( + SuspiciousOperation, + match=( + "We couldn't find a user with this sub but the email is already associated " + "with a registered user." + ), + ): + klass.get_or_create_user(access_token="test-token", id_token=None, payload=None) + + # Since the sub doesn't match, it should not create a new user + assert models.User.objects.count() == 1 + + +def test_authentication_getter_existing_user_with_email( + django_assert_num_queries, monkeypatch +): + """ + When the user's info contains an email and targets an existing user, + """ + klass = OIDCAuthenticationBackend() + user = UserFactory(full_name="John Doe", short_name="John") + + def get_userinfo_mocked(*args): + return { + "sub": user.sub, + "email": user.email, + "first_name": "John", + "last_name": "Doe", + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + # Only 1 query because email and names have not changed + with django_assert_num_queries(1): + authenticated_user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user == authenticated_user + + +@pytest.mark.parametrize( + "first_name, last_name, email", + [ + ("Jack", "Doe", "john.doe@example.com"), + ("John", "Duy", "john.doe@example.com"), + ("John", "Doe", "jack.duy@example.com"), + ("Jack", "Duy", "jack.duy@example.com"), + ], +) +def test_authentication_getter_existing_user_change_fields_sub( + first_name, last_name, email, django_assert_num_queries, monkeypatch +): + """ + It should update the email or name fields on the user when they change + and the user was identified by its "sub". + """ + klass = OIDCAuthenticationBackend() + user = UserFactory( + full_name="John Doe", short_name="John", email="john.doe@example.com" + ) + + def get_userinfo_mocked(*args): + return { + "sub": user.sub, + "email": email, + "first_name": first_name, + "last_name": last_name, + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + # One and only one additional update query when a field has changed + with django_assert_num_queries(3): + authenticated_user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user == authenticated_user + user.refresh_from_db() + assert user.email == email + assert user.full_name == f"{first_name:s} {last_name:s}" + assert user.short_name == first_name + + +@pytest.mark.parametrize( + "first_name, last_name, email", + [ + ("Jack", "Doe", "john.doe@example.com"), + ("John", "Duy", "john.doe@example.com"), + ], +) +def test_authentication_getter_existing_user_change_fields_email( + first_name, last_name, email, django_assert_num_queries, monkeypatch +): + """ + It should update the name fields on the user when they change + and the user was identified by its "email" as fallback. + """ + klass = OIDCAuthenticationBackend() + user = UserFactory( + full_name="John Doe", short_name="John", email="john.doe@example.com" + ) + + def get_userinfo_mocked(*args): + return { + "sub": "123", + "email": user.email, + "first_name": first_name, + "last_name": last_name, + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + # One and only one additional update query when a field has changed + with django_assert_num_queries(4): + authenticated_user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user == authenticated_user + user.refresh_from_db() + assert user.email == email + assert user.full_name == f"{first_name:s} {last_name:s}" + assert user.short_name == first_name + + +def test_authentication_getter_new_user_no_email(monkeypatch): + """ + If no user matches the user's info sub, a user should be created. + User's info doesn't contain an email, created user's email should be empty. + """ + klass = OIDCAuthenticationBackend() + + def get_userinfo_mocked(*args): + return {"sub": "123"} + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user.sub == "123" + assert user.email is None + assert user.full_name is None + assert user.short_name is None + assert user.has_usable_password() is False + assert models.User.objects.count() == 1 + + +def test_authentication_getter_new_user_with_email(monkeypatch): + """ + If no user matches the user's info sub, a user should be created. + User's email and name should be set on the identity. + The "email" field on the User model should not be set as it is reserved for staff users. + """ + klass = OIDCAuthenticationBackend() + + email = "calendars@example.com" + + def get_userinfo_mocked(*args): + return {"sub": "123", "email": email, "first_name": "John", "last_name": "Doe"} + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user.sub == "123" + assert user.email == email + assert user.full_name == "John Doe" + assert user.short_name == "John" + assert user.has_usable_password() is False + assert models.User.objects.count() == 1 + + +@override_settings(OIDC_OP_USER_ENDPOINT="http://oidc.endpoint.test/userinfo") +@responses.activate +def test_authentication_get_userinfo_json_response(): + """Test get_userinfo method with a JSON response.""" + + responses.add( + responses.GET, + re.compile(r".*/userinfo"), + json={ + "first_name": "John", + "last_name": "Doe", + "email": "john.doe@example.com", + }, + status=200, + ) + + oidc_backend = OIDCAuthenticationBackend() + result = oidc_backend.get_userinfo("fake_access_token", None, None) + + assert result["first_name"] == "John" + assert result["last_name"] == "Doe" + assert result["email"] == "john.doe@example.com" + + +@override_settings(OIDC_OP_USER_ENDPOINT="http://oidc.endpoint.test/userinfo") +@responses.activate +def test_authentication_get_userinfo_token_response(monkeypatch, settings): + """Test get_userinfo method with a token response.""" + settings.OIDC_RP_SIGN_ALGO = "HS256" # disable JWKS URL call + responses.add( + responses.GET, + re.compile(r".*/userinfo"), + body="fake.jwt.token", + status=200, + content_type="application/jwt", + ) + + def mock_verify_token(self, token): # pylint: disable=unused-argument + return { + "first_name": "Jane", + "last_name": "Doe", + "email": "jane.doe@example.com", + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "verify_token", mock_verify_token) + + oidc_backend = OIDCAuthenticationBackend() + result = oidc_backend.get_userinfo("fake_access_token", None, None) + + assert result["first_name"] == "Jane" + assert result["last_name"] == "Doe" + assert result["email"] == "jane.doe@example.com" + + +@override_settings(OIDC_OP_USER_ENDPOINT="http://oidc.endpoint.test/userinfo") +@responses.activate +def test_authentication_get_userinfo_invalid_response(settings): + """ + Test get_userinfo method with an invalid JWT response that + causes verify_token to raise an error. + """ + settings.OIDC_RP_SIGN_ALGO = "HS256" # disable JWKS URL call + responses.add( + responses.GET, + re.compile(r".*/userinfo"), + body="fake.jwt.token", + status=200, + content_type="application/jwt", + ) + + oidc_backend = OIDCAuthenticationBackend() + + with pytest.raises( + SuspiciousOperation, + match="User info response was not valid JWT", + ): + oidc_backend.get_userinfo("fake_access_token", None, None) + + +def test_authentication_getter_existing_disabled_user_via_sub( + django_assert_num_queries, monkeypatch +): + """ + If an existing user matches the sub but is disabled, + an error should be raised and a user should not be created. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory(is_active=False) + + def get_userinfo_mocked(*args): + return { + "sub": db_user.sub, + "email": db_user.email, + "first_name": "John", + "last_name": "Doe", + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + with ( + django_assert_num_queries(1), + pytest.raises(SuspiciousOperation, match="User account is disabled"), + ): + klass.get_or_create_user(access_token="test-token", id_token=None, payload=None) + + assert models.User.objects.count() == 1 + + +def test_authentication_getter_existing_disabled_user_via_email( + django_assert_num_queries, monkeypatch +): + """ + If an existing user does not match the sub but matches the email and is disabled, + an error should be raised and a user should not be created. + """ + + klass = OIDCAuthenticationBackend() + db_user = UserFactory(is_active=False) + + def get_userinfo_mocked(*args): + return { + "sub": "random", + "email": db_user.email, + "first_name": "John", + "last_name": "Doe", + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + with ( + django_assert_num_queries(2), + pytest.raises(SuspiciousOperation, match="User account is disabled"), + ): + klass.get_or_create_user(access_token="test-token", id_token=None, payload=None) + + assert models.User.objects.count() == 1 + + +@responses.activate +def test_authentication_session_tokens( + django_assert_num_queries, monkeypatch, rf, settings +): + """ + Test that the session contains oidc_refresh_token and oidc_access_token after authentication. + """ + settings.OIDC_OP_TOKEN_ENDPOINT = "http://oidc.endpoint.test/token" + settings.OIDC_OP_USER_ENDPOINT = "http://oidc.endpoint.test/userinfo" + settings.OIDC_OP_JWKS_ENDPOINT = "http://oidc.endpoint.test/jwks" + settings.OIDC_STORE_ACCESS_TOKEN = True + settings.OIDC_STORE_REFRESH_TOKEN = True + settings.OIDC_STORE_REFRESH_TOKEN_KEY = Fernet.generate_key() + + klass = OIDCAuthenticationBackend() + request = rf.get("/some-url", {"state": "test-state", "code": "test-code"}) + request.session = {} + + def verify_token_mocked(*args, **kwargs): + return {"sub": "123", "email": "test@example.com"} + + monkeypatch.setattr(OIDCAuthenticationBackend, "verify_token", verify_token_mocked) + + responses.add( + responses.POST, + re.compile(settings.OIDC_OP_TOKEN_ENDPOINT), + json={ + "access_token": "test-access-token", + "refresh_token": "test-refresh-token", + }, + status=200, + ) + + responses.add( + responses.GET, + re.compile(settings.OIDC_OP_USER_ENDPOINT), + json={"sub": "123", "email": "test@example.com"}, + status=200, + ) + + with django_assert_num_queries(27): + user = klass.authenticate( + request, + code="test-code", + nonce="test-nonce", + code_verifier="test-code-verifier", + ) + + assert user is not None + assert request.session["oidc_access_token"] == "test-access-token" + assert get_oidc_refresh_token(request.session) == "test-refresh-token" + + +@override_settings(OIDC_STORE_CLAIMS=["iss"]) +def test_authentication_store_claims_new_user(monkeypatch): + """ + Test that the claims are stored on the user when a new user is created. + """ + klass = OIDCAuthenticationBackend() + + email = "calendars@example.com" + + def get_userinfo_mocked(*args): + return { + "sub": "123", + "email": email, + "first_name": "John", + "last_name": "Doe", + "iss": "https://example.com", + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + assert user.sub == "123" + assert user.email == email + assert user.full_name == "John Doe" + assert user.short_name == "John" + assert user.has_usable_password() is False + assert user.claims == {"iss": "https://example.com"} + assert models.User.objects.count() == 1 + + +@override_settings(OIDC_STORE_CLAIMS=["iss"]) +def test_authentication_store_claims_existing_user(monkeypatch): + """ + Test that the claims are stored on the user when an existing user is authenticated. + """ + klass = OIDCAuthenticationBackend() + user = UserFactory( + email="calendars@example.com", sub="123", claims={"iss": "https://obsolete.com"} + ) + email = "calendars@example.com" + + def get_userinfo_mocked(*args): + return { + "sub": "123", + "email": email, + "first_name": "John", + "last_name": "Doe", + "iss": "https://example.com", + } + + monkeypatch.setattr(OIDCAuthenticationBackend, "get_userinfo", get_userinfo_mocked) + + user = klass.get_or_create_user( + access_token="test-token", id_token=None, payload=None + ) + + user.refresh_from_db() + assert user.sub == "123" + assert user.email == email + assert user.claims == {"iss": "https://example.com"} + assert models.User.objects.count() == 1 diff --git a/src/backend/core/tests/authentication/test_views.py b/src/backend/core/tests/authentication/test_views.py new file mode 100644 index 0000000..ebc92ba --- /dev/null +++ b/src/backend/core/tests/authentication/test_views.py @@ -0,0 +1,66 @@ +"""Unit tests for the Authentication Views.""" + +from unittest import mock + +from django.contrib.sessions.middleware import SessionMiddleware +from django.test import RequestFactory +from django.test.utils import override_settings + +import pytest +from mozilla_django_oidc.auth import ( + OIDCAuthenticationBackend as MozillaOIDCAuthenticationBackend, +) + +from core import factories +from core.authentication.backends import OIDCAuthenticationBackend +from core.authentication.views import ( + OIDCAuthenticationCallbackView, +) + +pytestmark = pytest.mark.django_db + + +@override_settings( + LOGIN_REDIRECT_URL_FAILURE="/auth/failure", + LOGIN_REDIRECT_URL="/auth/success", +) +@mock.patch.object( + MozillaOIDCAuthenticationBackend, + "get_token", + return_value={"id_token": "mocked_id_token", "access_token": "mocked_access_token"}, +) +@mock.patch.object( + MozillaOIDCAuthenticationBackend, "verify_token", return_value={"not": "needed"} +) +@mock.patch.object( + OIDCAuthenticationBackend, + "get_userinfo", + return_value={"sub": "mocked_sub", "email": "allowed@example.com"}, +) +def test_view_login_callback_authorized_by_default( + mocked_get_userinfo, mocked_verify_token, mocked_get_token +): + """By default, all users are authorized to login.""" + + user = factories.UserFactory(email="allowed@example.com") + + request = RequestFactory().get( + "/callback/", data={"state": "mocked_state", "code": "mocked_code"} + ) + request.user = user + + middleware = SessionMiddleware(get_response=lambda x: x) + middleware.process_request(request) + + mocked_state = "mocked_state" + request.session["oidc_states"] = {mocked_state: {"nonce": "mocked_nonce"}} + request.session.save() + + callback_view = OIDCAuthenticationCallbackView.as_view() + + response = callback_view(request) + mocked_get_token.assert_called_once() + mocked_verify_token.assert_called_once() + mocked_get_userinfo.assert_called_once() + assert response.status_code == 302 + assert response.url == "/auth/success" diff --git a/src/backend/core/tests/conftest.py b/src/backend/core/tests/conftest.py new file mode 100644 index 0000000..64c2a43 --- /dev/null +++ b/src/backend/core/tests/conftest.py @@ -0,0 +1,148 @@ +"""Fixtures for tests in the calendars core application""" + +import base64 +from unittest import mock + +from django.core.cache import cache +from django.db import connection + +import pytest +import responses +from cryptography.fernet import Fernet + +from core import factories +from core.tests.utils.urls import reload_urls + +USER = "user" +TEAM = "team" +VIA = [USER, TEAM] + + +@pytest.fixture(autouse=True) +def truncate_davical_tables(django_db_setup, django_db_blocker): + """Fixture to truncate DAViCal tables at the start of each test. + + DAViCal tables are created by the DAViCal container migrations, not Django. + We just truncate them to ensure clean state for each test. + """ + with django_db_blocker.unblock(): + with connection.cursor() as cursor: + # Truncate DAViCal tables if they exist (created by DAViCal container) + cursor.execute(""" + DO $$ + BEGIN + IF EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'principal') THEN + TRUNCATE TABLE principal CASCADE; + END IF; + IF EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'usr') THEN + TRUNCATE TABLE usr CASCADE; + END IF; + END $$; + """) + yield + + +@pytest.fixture(autouse=True) +def clear_cache(): + """Fixture to clear the cache after each test.""" + yield + cache.clear() + # Clear functools.cache for functions decorated with @functools.cache + + +@pytest.fixture +def mock_user_teams(): + """Mock for the "teams" property on the User model.""" + with mock.patch( + "core.models.User.teams", new_callable=mock.PropertyMock + ) as mock_teams: + yield mock_teams + + +def resource_server_backend_setup(settings): + """ + A fixture to create a user token for testing. + """ + assert ( + settings.OIDC_RS_BACKEND_CLASS + == "lasuite.oidc_resource_server.backend.ResourceServerBackend" + ) + + settings.OIDC_RESOURCE_SERVER_ENABLED = True + settings.OIDC_RS_CLIENT_ID = "some_client_id" + settings.OIDC_RS_CLIENT_SECRET = "some_client_secret" + + settings.OIDC_OP_URL = "https://oidc.example.com" + settings.OIDC_VERIFY_SSL = False + settings.OIDC_TIMEOUT = 5 + settings.OIDC_PROXY = None + settings.OIDC_OP_JWKS_ENDPOINT = "https://oidc.example.com/jwks" + settings.OIDC_OP_INTROSPECTION_ENDPOINT = "https://oidc.example.com/introspect" + settings.OIDC_RS_SCOPES = ["openid", "groups"] + settings.OIDC_RS_ALLOWED_AUDIENCES = ["some_service_provider"] + + +@pytest.fixture +def resource_server_backend_conf(settings): + """ + A fixture to create a user token for testing. + """ + resource_server_backend_setup(settings) + reload_urls() + + +@pytest.fixture +def resource_server_backend(settings): + """ + A fixture to create a user token for testing. + Including a mocked introspection endpoint. + """ + resource_server_backend_setup(settings) + reload_urls() + + with responses.RequestsMock() as rsps: + rsps.add( + responses.POST, + "https://oidc.example.com/introspect", + json={ + "iss": "https://oidc.example.com", + "aud": "some_client_id", # settings.OIDC_RS_CLIENT_ID + "sub": "very-specific-sub", + "client_id": "some_service_provider", + "scope": "openid groups", + "active": True, + }, + ) + + yield rsps + + +@pytest.fixture +def user_specific_sub(): + """ + A fixture to create a user token for testing. + """ + user = factories.UserFactory(sub="very-specific-sub") + + yield user + + +def build_authorization_bearer(token): + """ + Build an Authorization Bearer header value from a token. + + This can be used like this: + client.post( + ... + HTTP_AUTHORIZATION=f"Bearer {build_authorization_bearer('some_token')}", + ) + """ + return base64.b64encode(token.encode("utf-8")).decode("utf-8") + + +@pytest.fixture +def user_token(): + """ + A fixture to create a user token for testing. + """ + return build_authorization_bearer("some_token") diff --git a/src/backend/core/tests/external_api/test_external_api_users.py b/src/backend/core/tests/external_api/test_external_api_users.py new file mode 100644 index 0000000..b59dc07 --- /dev/null +++ b/src/backend/core/tests/external_api/test_external_api_users.py @@ -0,0 +1,152 @@ +""" +Tests for the Resource Server API for users. + +Not testing external API endpoints that are already tested in the /api +because the resource server viewsets inherit from the api viewsets. + +""" + +import pytest +from rest_framework.test import APIClient + +from core import factories +from core.api import serializers +from core.tests.utils.urls import reload_urls + +pytestmark = pytest.mark.django_db + +# pylint: disable=unused-argument + + +def test_api_users_me_anonymous_public_standalone(): + """ + Anonymous users should not be allowed to retrieve their own user information from external + API if resource server is not enabled. + """ + reload_urls() + response = APIClient().get("/external_api/v1.0/users/me/") + + assert response.status_code == 404 + + +def test_api_users_me_connected_not_resource_server(): + """ + Connected users should not be allowed to retrieve their own user information from external + API if resource server is not enabled. + """ + reload_urls() + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + response = client.get("/external_api/v1.0/users/me/") + + assert response.status_code == 404 + + +def test_api_users_me_connected_resource_server( + user_token, resource_server_backend, user_specific_sub +): + """ + Connected users should be allowed to retrieve their own user information from external API + if resource server is enabled. + """ + client = APIClient() + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_token}") + + response = client.get("/external_api/v1.0/users/me/") + + assert response.status_code == 200 + data = response.json() + assert data["id"] == str(user_specific_sub.id) + assert data["email"] == user_specific_sub.email + + +def test_api_users_me_connected_resource_server_with_invalid_token( + user_token, resource_server_backend +): + """ + Connected users should not be allowed to retrieve their own user information from external API + if resource server is enabled with an invalid token. + """ + client = APIClient() + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_token}") + + response = client.get("/external_api/v1.0/users/me/") + + assert response.status_code == 401 + + +# Non allowed actions on resource server. + + +def test_api_users_list_resource_server_not_allowed( + user_token, resource_server_backend, user_specific_sub +): + """ + Connected users should notbe allowed to list users from a resource server. + """ + client = APIClient() + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_token}") + + response = client.get("/external_api/v1.0/users/") + + assert response.status_code == 403 + + +def test_api_users_retrieve_resource_server_not_allowed( + user_token, resource_server_backend, user_specific_sub +): + """ + Connected users should notbe allowed to list users from a resource server. + """ + client = APIClient() + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_token}") + + other_user = factories.UserFactory() + + response = client.get(f"/external_api/v1.0/users/{other_user.id!s}/") + + assert response.status_code == 403 + + +def test_api_users_put_patch_resource_server_not_allowed( + user_token, resource_server_backend, user_specific_sub +): + """ + Connected users should notbe allowed to list users from a resource server. + """ + client = APIClient() + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_token}") + + other_user = factories.UserFactory() + + new_user_values = serializers.UserSerializer(instance=factories.UserFactory()).data + response = client.put( + f"/external_api/v1.0/users/{other_user.id!s}/", new_user_values + ) + + assert response.status_code == 403 + + response = client.patch( + f"/external_api/v1.0/users/{other_user.id!s}/", + {"email": "new_email@example.com"}, + ) + + assert response.status_code == 403 + + +def test_api_users_delete_resource_server_not_allowed( + user_token, resource_server_backend, user_specific_sub +): + """ + Connected users should notbe allowed to list users from a resource server. + """ + client = APIClient() + client.credentials(HTTP_AUTHORIZATION=f"Bearer {user_token}") + + other_user = factories.UserFactory() + + response = client.delete(f"/external_api/v1.0/users/{other_user.id!s}/") + + assert response.status_code == 403 diff --git a/src/backend/core/tests/swagger/__init__.py b/src/backend/core/tests/swagger/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/core/tests/swagger/test_openapi_schema.py b/src/backend/core/tests/swagger/test_openapi_schema.py new file mode 100644 index 0000000..74b0f18 --- /dev/null +++ b/src/backend/core/tests/swagger/test_openapi_schema.py @@ -0,0 +1,42 @@ +""" +Test suite for generated openapi schema. +""" + +import json +from io import StringIO + +from django.core.management import call_command +from django.test import Client + +import pytest + +pytestmark = pytest.mark.django_db + + +def test_openapi_client_schema(): + """ + Generated and served OpenAPI client schema should be correct. + """ + # Start by generating the swagger.json file + output = StringIO() + call_command( + "spectacular", + "--api-version", + "v1.0", + "--urlconf", + "core.urls", + "--format", + "openapi-json", + "--file", + "core/tests/swagger/swagger.json", + stdout=output, + ) + assert output.getvalue() == "" + + response = Client().get("/api/v1.0/swagger.json") + + assert response.status_code == 200 + with open( + "core/tests/swagger/swagger.json", "r", encoding="utf-8" + ) as expected_schema: + assert response.json() == json.load(expected_schema) diff --git a/src/backend/core/tests/test_api_config.py b/src/backend/core/tests/test_api_config.py new file mode 100644 index 0000000..20fdcee --- /dev/null +++ b/src/backend/core/tests/test_api_config.py @@ -0,0 +1,161 @@ +""" +Test config API endpoints in the calendars core app. +""" + +import json + +from django.test import override_settings + +import pytest +from rest_framework.status import ( + HTTP_200_OK, +) +from rest_framework.test import APIClient + +from core import factories + +pytestmark = pytest.mark.django_db + + +@override_settings( + FRONTEND_THEME="test-theme", + FRONTEND_MORE_LINK="https://test.com", + FRONTEND_FEEDBACK_BUTTON_SHOW=True, + FRONTEND_FEEDBACK_BUTTON_IDLE=False, + FRONTEND_FEEDBACK_ITEMS={"form": {"url": "https://test.com"}}, + FRONTEND_FEEDBACK_MESSAGES_WIDGET_ENABLED=True, + FRONTEND_FEEDBACK_MESSAGES_WIDGET_API_URL="https://test.com", + FRONTEND_FEEDBACK_MESSAGES_WIDGET_CHANNEL="test", + FRONTEND_FEEDBACK_MESSAGES_WIDGET_PATH="https://test.com", + FRONTEND_HIDE_GAUFRE=True, + MEDIA_BASE_URL="http://testserver/", + SENTRY_DSN="https://sentry.test/123", + THEME_CUSTOMIZATION_FILE_PATH="", +) +@pytest.mark.parametrize("is_authenticated", [False, True]) +def test_api_config(is_authenticated): + """Anonymous users should be allowed to get the configuration.""" + client = APIClient() + + if is_authenticated: + user = factories.UserFactory() + client.force_login(user) + + response = client.get("/api/v1.0/config/") + assert response.status_code == HTTP_200_OK + assert response.json() == { + "ENVIRONMENT": "test", + "FRONTEND_THEME": "test-theme", + "FRONTEND_MORE_LINK": "https://test.com", + "FRONTEND_FEEDBACK_BUTTON_SHOW": True, + "FRONTEND_FEEDBACK_BUTTON_IDLE": False, + "FRONTEND_FEEDBACK_ITEMS": {"form": {"url": "https://test.com"}}, + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_ENABLED": True, + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_API_URL": "https://test.com", + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_CHANNEL": "test", + "FRONTEND_FEEDBACK_MESSAGES_WIDGET_PATH": "https://test.com", + "FRONTEND_HIDE_GAUFRE": True, + "LANGUAGES": [ + ["en-us", "English"], + ["fr-fr", "French"], + ["de-de", "German"], + ["nl-nl", "Dutch"], + ], + "LANGUAGE_CODE": "en-us", + "MEDIA_BASE_URL": "http://testserver/", + "SENTRY_DSN": "https://sentry.test/123", + "theme_customization": {}, + } + + +@override_settings( + THEME_CUSTOMIZATION_FILE_PATH="/not/existing/file.json", +) +@pytest.mark.parametrize("is_authenticated", [False, True]) +def test_api_config_with_invalid_theme_customization_file(is_authenticated): + """Anonymous users should be allowed to get the configuration.""" + client = APIClient() + + if is_authenticated: + user = factories.UserFactory() + client.force_login(user) + + response = client.get("/api/v1.0/config/") + assert response.status_code == HTTP_200_OK + content = response.json() + assert content["theme_customization"] == {} + + +@override_settings( + THEME_CUSTOMIZATION_FILE_PATH="/configuration/theme/invalid.json", +) +@pytest.mark.parametrize("is_authenticated", [False, True]) +def test_api_config_with_invalid_json_theme_customization_file(is_authenticated, fs): + """Anonymous users should be allowed to get the configuration.""" + fs.create_file( + "/configuration/theme/invalid.json", + contents="invalid json", + ) + client = APIClient() + + if is_authenticated: + user = factories.UserFactory() + client.force_login(user) + + response = client.get("/api/v1.0/config/") + assert response.status_code == HTTP_200_OK + content = response.json() + assert content["theme_customization"] == {} + + +@override_settings( + THEME_CUSTOMIZATION_FILE_PATH="/configuration/theme/default.json", +) +@pytest.mark.parametrize("is_authenticated", [False, True]) +def test_api_config_with_theme_customization(is_authenticated, fs): + """Anonymous users should be allowed to get the configuration.""" + fs.create_file( + "/configuration/theme/default.json", + contents=json.dumps( + { + "colors": { + "primary": "#000000", + "secondary": "#000000", + }, + } + ), + ) + client = APIClient() + + if is_authenticated: + user = factories.UserFactory() + client.force_login(user) + + response = client.get("/api/v1.0/config/") + assert response.status_code == HTTP_200_OK + content = response.json() + assert content["theme_customization"] == { + "colors": { + "primary": "#000000", + "secondary": "#000000", + }, + } + + +@pytest.mark.parametrize("is_authenticated", [False, True]) +def test_api_config_with_original_theme_customization(is_authenticated, settings): + """Anonymous users should be allowed to get the configuration.""" + client = APIClient() + + if is_authenticated: + user = factories.UserFactory() + client.force_login(user) + + response = client.get("/api/v1.0/config/") + assert response.status_code == HTTP_200_OK + content = response.json() + + with open(settings.THEME_CUSTOMIZATION_FILE_PATH, "r", encoding="utf-8") as f: + theme_customization = json.load(f) + + assert content["theme_customization"] == theme_customization diff --git a/src/backend/core/tests/test_api_users.py b/src/backend/core/tests/test_api_users.py new file mode 100644 index 0000000..bcd320e --- /dev/null +++ b/src/backend/core/tests/test_api_users.py @@ -0,0 +1,638 @@ +""" +Test users API endpoints in the calendars core app. +""" + +import pytest +from rest_framework.test import APIClient + +from core import factories, models +from core.api import serializers + +pytestmark = pytest.mark.django_db + + +def test_api_users_list_anonymous(): + """Anonymous users should not be allowed to list users.""" + factories.UserFactory() + client = APIClient() + response = client.get("/api/v1.0/users/") + assert response.status_code == 401 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "not_authenticated", + "detail": "Authentication credentials were not provided.", + }, + ], + "type": "client_error", + } + + +def test_api_users_list_authenticated(): + """ + Authenticated users should not be able to list users without a query. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + factories.UserFactory.create_batch(2) + response = client.get( + "/api/v1.0/users/", + ) + assert response.status_code == 200 + assert response.json() == [] + + +def test_api_users_list_query_inactive(): + """Inactive users should not be listed.""" + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + factories.UserFactory(email="john.doe@example.com", is_active=False) + lennon = factories.UserFactory(email="john.lennon@example.com") + + # Use email query to get exact match + response = client.get("/api/v1.0/users/?q=john.lennon@example.com") + + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [str(lennon.id)] + + # Inactive user should not be returned even with exact match + response = client.get("/api/v1.0/users/?q=john.doe@example.com") + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [] + + +def test_api_users_list_query_short_queries(): + """ + Queries shorter than 5 characters should return an empty result set. + """ + + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + factories.UserFactory(email="john.doe@example.com") + factories.UserFactory(email="john.lennon@example.com") + + response = client.get("/api/v1.0/users/?q=jo") + assert response.status_code == 200 + assert response.json() == [] + + response = client.get("/api/v1.0/users/?q=john") + assert response.status_code == 200 + assert response.json() == [] + + # Non-email queries (without @) return empty + response = client.get("/api/v1.0/users/?q=john.") + assert response.status_code == 200 + assert response.json() == [] + + +def test_api_users_list_limit(settings): + """ + Authenticated users should be able to list users and the number of results + should be limited to 10. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + # Use a base name with a length equal 5 to test that the limit is applied + base_name = "alice" + for i in range(15): + factories.UserFactory(email=f"{base_name}.{i}@example.com") + + # Non-email queries (without @) return empty + response = client.get( + "/api/v1.0/users/?q=alice", + ) + assert response.status_code == 200 + assert response.json() == [] + + # Email queries require exact match + settings.API_USERS_LIST_LIMIT = 100 + response = client.get( + "/api/v1.0/users/?q=alice.0@example.com", + ) + assert response.status_code == 200 + assert len(response.json()) == 1 + + +def test_api_users_list_throttling_authenticated(settings): + """ + Authenticated users should be throttled. + """ + user = factories.UserFactory() + client = APIClient() + client.force_login(user) + + settings.REST_FRAMEWORK["DEFAULT_THROTTLE_RATES"]["user_list_burst"] = "3/minute" + + for _i in range(3): + response = client.get( + "/api/v1.0/users/?q=alice", + ) + assert response.status_code == 200 + + response = client.get( + "/api/v1.0/users/?q=alice", + ) + assert response.status_code == 429 + + +def test_api_users_list_query_email(): + """ + Authenticated users should be able to list users and filter by email. + Only exact email matches are returned (case-insensitive). + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + dave = factories.UserFactory(email="david.bowman@work.com") + factories.UserFactory(email="nicole.bowman@work.com") + + # Exact match works + response = client.get( + "/api/v1.0/users/?q=david.bowman@work.com", + ) + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [str(dave.id)] + + # Case-insensitive match works + response = client.get( + "/api/v1.0/users/?q=David.Bowman@Work.COM", + ) + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [str(dave.id)] + + # Typos don't match (exact match only) + response = client.get( + "/api/v1.0/users/?q=davig.bovman@worm.com", + ) + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [] + + response = client.get( + "/api/v1.0/users/?q=davig.bovman@worm.cop", + ) + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [] + + +def test_api_users_list_query_email_matching(): + """Email queries return exact matches only (case-insensitive).""" + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + user1 = factories.UserFactory(email="alice.johnson@example.gouv.fr") + user2 = factories.UserFactory(email="alice.johnnson@example.gouv.fr") + user3 = factories.UserFactory(email="alice.kohlson@example.gouv.fr") + user4 = factories.UserFactory(email="alicia.johnnson@example.gouv.fr") + user5 = factories.UserFactory(email="alicia.johnnson@example.gov.uk") + factories.UserFactory(email="alice.thomson@example.gouv.fr") + + # Exact match returns only that user + response = client.get( + "/api/v1.0/users/?q=alice.johnson@example.gouv.fr", + ) + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [str(user1.id)] + + # Different email returns different user + response = client.get("/api/v1.0/users/?q=alicia.johnnson@example.gouv.fr") + assert response.status_code == 200 + user_ids = [user["id"] for user in response.json()] + assert user_ids == [str(user4.id)] + + +def test_api_users_retrieve_me_anonymous(): + """Anonymous users should not be allowed to list users.""" + factories.UserFactory.create_batch(2) + client = APIClient() + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 401 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "not_authenticated", + "detail": "Authentication credentials were not provided.", + }, + ], + "type": "client_error", + } + + +def test_api_users_retrieve_me_authenticated(): + """Authenticated users should be able to retrieve their own user via the "/users/me" path.""" + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + factories.UserFactory.create_batch(2) + response = client.get( + "/api/v1.0/users/me/", + ) + + assert response.status_code == 200 + assert response.json() == { + "id": str(user.id), + "email": user.email, + "full_name": user.full_name, + "short_name": user.short_name, + "language": user.language, + } + + +def test_api_users_retrieve_anonymous(): + """Anonymous users should not be allowed to retrieve a user.""" + client = APIClient() + user = factories.UserFactory() + response = client.get(f"/api/v1.0/users/{user.id!s}/") + + assert response.status_code == 401 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "not_authenticated", + "detail": "Authentication credentials were not provided.", + }, + ], + "type": "client_error", + } + + +def test_api_users_retrieve_authenticated_self(): + """ + Authenticated users should be allowed to retrieve their own user. + The returned object should not contain the password. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + response = client.get( + f"/api/v1.0/users/{user.id!s}/", + ) + assert response.status_code == 405 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "method_not_allowed", + "detail": 'Method "GET" not allowed.', + }, + ], + "type": "client_error", + } + + +def test_api_users_retrieve_authenticated_other(): + """ + Authenticated users should be able to retrieve another user's detail view with + limited information. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + other_user = factories.UserFactory() + + response = client.get( + f"/api/v1.0/users/{other_user.id!s}/", + ) + assert response.status_code == 405 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "method_not_allowed", + "detail": 'Method "GET" not allowed.', + }, + ], + "type": "client_error", + } + + +def test_api_users_create_anonymous(): + """Anonymous users should not be able to create users via the API.""" + response = APIClient().post( + "/api/v1.0/users/", + { + "language": "fr-fr", + "password": "mypassword", + }, + ) + assert response.status_code == 401 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "not_authenticated", + "detail": "Authentication credentials were not provided.", + }, + ], + "type": "client_error", + } + + assert models.User.objects.exists() is False + + +def test_api_users_create_authenticated(): + """Authenticated users should not be able to create users via the API.""" + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + response = client.post( + "/api/v1.0/users/", + { + "language": "fr-fr", + "password": "mypassword", + }, + format="json", + ) + assert response.status_code == 405 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "method_not_allowed", + "detail": 'Method "POST" not allowed.', + }, + ], + "type": "client_error", + } + + assert models.User.objects.exclude(id=user.id).exists() is False + + +def test_api_users_update_anonymous(): + """Anonymous users should not be able to update users via the API.""" + user = factories.UserFactory() + + old_user_values = dict(serializers.UserSerializer(instance=user).data) + new_user_values = serializers.UserSerializer(instance=factories.UserFactory()).data + + response = APIClient().put( + f"/api/v1.0/users/{user.id!s}/", + new_user_values, + format="json", + ) + + assert response.status_code == 401 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "not_authenticated", + "detail": "Authentication credentials were not provided.", + }, + ], + "type": "client_error", + } + + user.refresh_from_db() + user_values = dict(serializers.UserSerializer(instance=user).data) + for key, value in user_values.items(): + assert value == old_user_values[key] + + +def test_api_users_update_authenticated_self(): + """ + Authenticated users should be able to update their own user but only "language" + and "timezone" fields. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + old_user_values = dict(serializers.UserSerializer(instance=user).data) + new_user_values = dict( + serializers.UserSerializer(instance=factories.UserFactory()).data + ) + + response = client.put( + f"/api/v1.0/users/{user.id!s}/", + new_user_values, + format="json", + ) + + assert response.status_code == 200 + user.refresh_from_db() + user_values = dict(serializers.UserSerializer(instance=user).data) + for key, value in user_values.items(): + if key in ["language", "timezone"]: + assert value == new_user_values[key] + else: + assert value == old_user_values[key] + + +def test_api_users_update_authenticated_other(): + """Authenticated users should not be allowed to update other users.""" + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + user = factories.UserFactory() + old_user_values = dict(serializers.UserSerializer(instance=user).data) + new_user_values = serializers.UserSerializer(instance=factories.UserFactory()).data + + response = client.put( + f"/api/v1.0/users/{user.id!s}/", + new_user_values, + format="json", + ) + + assert response.status_code == 403 + user.refresh_from_db() + user_values = dict(serializers.UserSerializer(instance=user).data) + for key, value in user_values.items(): + assert value == old_user_values[key] + + +def test_api_users_patch_anonymous(): + """Anonymous users should not be able to patch users via the API.""" + user = factories.UserFactory() + + old_user_values = dict(serializers.UserSerializer(instance=user).data) + new_user_values = dict( + serializers.UserSerializer(instance=factories.UserFactory()).data + ) + + for key, new_value in new_user_values.items(): + response = APIClient().patch( + f"/api/v1.0/users/{user.id!s}/", + {key: new_value}, + format="json", + ) + assert response.status_code == 401 + assert response.json() == { + "errors": [ + { + "attr": None, + "code": "not_authenticated", + "detail": "Authentication credentials were not provided.", + }, + ], + "type": "client_error", + } + + user.refresh_from_db() + user_values = dict(serializers.UserSerializer(instance=user).data) + for key, value in user_values.items(): + assert value == old_user_values[key] + + +def test_api_users_patch_authenticated_self(): + """ + Authenticated users should be able to patch their own user but only "language" + and "timezone" fields. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + old_user_values = dict(serializers.UserSerializer(instance=user).data) + new_user_values = dict( + serializers.UserSerializer(instance=factories.UserFactory()).data + ) + + for key, new_value in new_user_values.items(): + response = client.patch( + f"/api/v1.0/users/{user.id!s}/", + {key: new_value}, + format="json", + ) + assert response.status_code == 200 + + user.refresh_from_db() + user_values = dict(serializers.UserSerializer(instance=user).data) + for key, value in user_values.items(): + if key in ["language", "timezone"]: + assert value == new_user_values[key] + else: + assert value == old_user_values[key] + + +def test_api_users_patch_authenticated_other(): + """Authenticated users should not be allowed to patch other users.""" + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + user = factories.UserFactory() + old_user_values = dict(serializers.UserSerializer(instance=user).data) + new_user_values = dict( + serializers.UserSerializer(instance=factories.UserFactory()).data + ) + + for key, new_value in new_user_values.items(): + response = client.put( + f"/api/v1.0/users/{user.id!s}/", + {key: new_value}, + format="json", + ) + assert response.status_code == 403 + + user.refresh_from_db() + user_values = dict(serializers.UserSerializer(instance=user).data) + for key, value in user_values.items(): + assert value == old_user_values[key] + + +def test_api_users_delete_list_anonymous(): + """Anonymous users should not be allowed to delete a list of users.""" + factories.UserFactory.create_batch(2) + + client = APIClient() + response = client.delete("/api/v1.0/users/") + + assert response.status_code == 401 + assert models.User.objects.count() == 2 + + +def test_api_users_delete_list_authenticated(): + """Authenticated users should not be allowed to delete a list of users.""" + factories.UserFactory.create_batch(2) + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + response = client.delete( + "/api/v1.0/users/", + ) + + assert response.status_code == 405 + assert models.User.objects.count() == 3 + + +def test_api_users_delete_anonymous(): + """Anonymous users should not be allowed to delete a user.""" + user = factories.UserFactory() + + response = APIClient().delete(f"/api/v1.0/users/{user.id!s}/") + + assert response.status_code == 401 + assert models.User.objects.count() == 1 + + +def test_api_users_delete_authenticated(): + """ + Authenticated users should not be allowed to delete a user other than themselves. + """ + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + other_user = factories.UserFactory() + + response = client.delete( + f"/api/v1.0/users/{other_user.id!s}/", + ) + + assert response.status_code == 405 + assert models.User.objects.count() == 2 + + +def test_api_users_delete_self(): + """Authenticated users should not be able to delete their own user.""" + user = factories.UserFactory() + + client = APIClient() + client.force_login(user) + + response = client.delete( + f"/api/v1.0/users/{user.id!s}/", + ) + + assert response.status_code == 405 + assert models.User.objects.count() == 1 diff --git a/src/backend/core/tests/test_caldav_service.py b/src/backend/core/tests/test_caldav_service.py new file mode 100644 index 0000000..3baa426 --- /dev/null +++ b/src/backend/core/tests/test_caldav_service.py @@ -0,0 +1,71 @@ +"""Tests for CalDAV service integration with DAViCal.""" + +from unittest.mock import Mock, patch + +from django.conf import settings + +import pytest + +from core import factories +from core.services.caldav_service import CalendarService, DAViCalClient + + +@pytest.mark.django_db +class TestDAViCalClient: + """Tests for DAViCalClient authentication and communication.""" + + def test_get_client_sends_x_forwarded_user_header(self): + """Test that DAVClient is configured with X-Forwarded-User header.""" + user = factories.UserFactory(email="test@example.com") + client = DAViCalClient() + + dav_client = client._get_client(user) + + # Verify the client is configured correctly + assert dav_client.username == user.email + # Password should be empty (None or empty string) for external auth + assert not dav_client.password or dav_client.password == "" + + # Verify the X-Forwarded-User header is set + # The caldav library stores headers as a CaseInsensitiveDict + assert hasattr(dav_client, "headers") + assert "X-Forwarded-User" in dav_client.headers + assert dav_client.headers["X-Forwarded-User"] == user.email + + @pytest.mark.skipif( + not getattr(settings, "DAVICAL_URL", None), + reason="DAViCal URL not configured", + ) + def test_create_calendar_authenticates_with_davical(self): + """Test that calendar creation authenticates successfully with DAViCal.""" + user = factories.UserFactory(email="test@example.com") + client = DAViCalClient() + + # Ensure user exists in DAViCal + client.ensure_user_exists(user) + + # Try to create a calendar - this should authenticate successfully + calendar_path = client.create_calendar( + user, calendar_name="Test Calendar", calendar_id="test-calendar-id" + ) + + # Verify calendar path was returned + assert calendar_path is not None + assert calendar_path.startswith("/caldav.php/") + assert user.email in calendar_path + + def test_calendar_service_creates_calendar(self): + """Test that CalendarService can create a calendar through DAViCal.""" + user = factories.UserFactory(email="test@example.com") + service = CalendarService() + + # Create a calendar + calendar = service.create_calendar(user, name="My Calendar", color="#ff0000") + + # Verify calendar was created + assert calendar is not None + assert calendar.owner == user + assert calendar.name == "My Calendar" + assert calendar.color == "#ff0000" + assert calendar.davical_path is not None + assert calendar.davical_path.startswith("/caldav.php/") diff --git a/src/backend/core/tests/test_models_users.py b/src/backend/core/tests/test_models_users.py new file mode 100644 index 0000000..1bba4e2 --- /dev/null +++ b/src/backend/core/tests/test_models_users.py @@ -0,0 +1,46 @@ +""" +Unit tests for the User model +""" + +from unittest import mock + +from django.core.exceptions import ValidationError + +import pytest + +from core import factories, models + +pytestmark = pytest.mark.django_db + + +def test_models_users_str(): + """The str representation should be the email.""" + user = factories.UserFactory() + assert str(user) == user.email + + +def test_models_users_id_unique(): + """The "id" field should be unique.""" + user = factories.UserFactory() + with pytest.raises(ValidationError, match="User with this Id already exists."): + factories.UserFactory(id=user.id) + + +def test_models_users_send_mail_main_existing(): + """The "email_user' method should send mail to the user's email address.""" + user = factories.UserFactory() + + with mock.patch("django.core.mail.send_mail") as mock_send: + user.email_user("my subject", "my message") + + mock_send.assert_called_once_with("my subject", "my message", None, [user.email]) + + +def test_models_users_send_mail_main_missing(): + """The "email_user' method should fail if the user has no email address.""" + user = factories.UserFactory(email=None) + + with pytest.raises(ValueError) as excinfo: + user.email_user("my subject", "my message") + + assert str(excinfo.value) == "User has no email address." diff --git a/src/backend/core/tests/test_settings.py b/src/backend/core/tests/test_settings.py new file mode 100644 index 0000000..a3af681 --- /dev/null +++ b/src/backend/core/tests/test_settings.py @@ -0,0 +1,30 @@ +""" +Unit tests for the User model +""" + +import pytest + +from calendars.settings import Base + + +def test_invalid_settings_oidc_email_configuration(): + """ + The OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION and OIDC_ALLOW_DUPLICATE_EMAILS settings + should not be both set to True simultaneously. + """ + + class TestSettings(Base): + """Fake test settings.""" + + OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION = True + OIDC_ALLOW_DUPLICATE_EMAILS = True + + # The validation is performed during post_setup + with pytest.raises(ValueError) as excinfo: + TestSettings().post_setup() + + # Check the exception message + assert str(excinfo.value) == ( + "Both OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION and " + "OIDC_ALLOW_DUPLICATE_EMAILS cannot be set to True simultaneously. " + ) diff --git a/src/backend/core/tests/utils/urls.py b/src/backend/core/tests/utils/urls.py new file mode 100644 index 0000000..16f6d1f --- /dev/null +++ b/src/backend/core/tests/utils/urls.py @@ -0,0 +1,20 @@ +"""Utils for testing URLs.""" + +import importlib + +from django.urls import clear_url_caches + + +def reload_urls(): + """ + Reload the URLs. Since the url are loaded based on a + settings value, we need to reload the urls to make the + URL settings based condition effective. + """ + import core.urls # pylint:disable=import-outside-toplevel # noqa: PLC0415 + + import calendars.urls # pylint:disable=import-outside-toplevel # noqa: PLC0415 + + importlib.reload(core.urls) + importlib.reload(calendars.urls) + clear_url_caches() diff --git a/src/backend/core/urls.py b/src/backend/core/urls.py new file mode 100644 index 0000000..9d17eed --- /dev/null +++ b/src/backend/core/urls.py @@ -0,0 +1,61 @@ +"""URL configuration for the core app.""" + +from django.conf import settings +from django.urls import include, path, re_path + +from lasuite.oidc_login.urls import urlpatterns as oidc_urls +from rest_framework.routers import DefaultRouter + +from core.api import viewsets +from core.api.viewsets_caldav import CalDAVProxyView +from core.external_api import viewsets as external_api_viewsets + +# - Main endpoints +router = DefaultRouter() +router.register("users", viewsets.UserViewSet, basename="users") +router.register("calendars", viewsets.CalendarViewSet, basename="calendars") + +urlpatterns = [ + path( + f"api/{settings.API_VERSION}/", + include( + [ + *router.urls, + *oidc_urls, + # CalDAV proxy - root path (must come before catch-all to match /caldav exactly) + path("caldav", CalDAVProxyView.as_view(), name="caldav-root"), + path("caldav/", CalDAVProxyView.as_view(), name="caldav-root-slash"), + # CalDAV proxy - catch all paths with content + re_path( + r"^caldav/(?P.+)$", + CalDAVProxyView.as_view(), + name="caldav-proxy", + ), + ] + ), + ), + path(f"api/{settings.API_VERSION}/config/", viewsets.ConfigView.as_view()), +] + + +if settings.OIDC_RESOURCE_SERVER_ENABLED: + # - Resource server routes + external_api_router = DefaultRouter() + + users_access_config = settings.EXTERNAL_API.get("users", {}) + if users_access_config.get("enabled", False): + external_api_router.register( + "users", + external_api_viewsets.ResourceServerUserViewSet, + basename="resource_server_users", + ) + + external_api_urls = [*external_api_router.urls] + + if external_api_urls: + urlpatterns.append( + path( + f"external_api/{settings.API_VERSION}/", + include(external_api_urls), + ) + ) diff --git a/src/backend/e2e/__init__.py b/src/backend/e2e/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/e2e/management/commands/__init__.py b/src/backend/e2e/management/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/backend/e2e/serializers.py b/src/backend/e2e/serializers.py new file mode 100644 index 0000000..62ce878 --- /dev/null +++ b/src/backend/e2e/serializers.py @@ -0,0 +1,12 @@ +"""Serializers for E2E tests.""" + +from rest_framework import serializers + + +# Suppress the warning about not implementing `create` and `update` methods +# since we don't use a model and only rely on the serializer for validation +# pylint: disable=abstract-method +class E2EAuthSerializer(serializers.Serializer): + """Serializer for E2E authentication.""" + + email = serializers.EmailField(required=True) diff --git a/src/backend/e2e/tests/test_api_e2e.py b/src/backend/e2e/tests/test_api_e2e.py new file mode 100644 index 0000000..58123a4 --- /dev/null +++ b/src/backend/e2e/tests/test_api_e2e.py @@ -0,0 +1,83 @@ +""" +Test e2e API endpoints. +""" + +from django.test.utils import override_settings + +import pytest +from rest_framework.test import APIClient + +from core.tests.utils.urls import reload_urls + +pytestmark = pytest.mark.django_db + + +def test_api_e2e_user_auth_no_urls(): + """E2E URLs not enabled should 404.""" + client = APIClient() + + response = client.post("/api/v1.0/e2e/user-auth/", {"email": "test@example.com"}) + assert response.status_code == 404 + + +@override_settings(LOAD_E2E_URLS=True) +def test_api_e2e_user_auth_anonymous(): + """Anonymous users should be allowed to create and login a user.""" + reload_urls() + client = APIClient() + + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 401 + + response = client.post("/api/v1.0/e2e/user-auth/", {"email": "test@example.com"}) + assert response.status_code == 200 + assert response.json() == {"email": "test@example.com"} + + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 200 + assert response.json()["email"] == "test@example.com" + + +@override_settings(LOAD_E2E_URLS=True) +def test_api_e2e_user_auth_authenticated(): + """Authenticated users should be allowed to create and login a new user.""" + reload_urls() + client = APIClient() + + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 401 + + response = client.post("/api/v1.0/e2e/user-auth/", {"email": "test@example.com"}) + assert response.status_code == 200 + assert response.json() == {"email": "test@example.com"} + + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 200 + assert response.json()["email"] == "test@example.com" + + response = client.post("/api/v1.0/e2e/user-auth/", {"email": "test2@example.com"}) + assert response.status_code == 200 + assert response.json() == {"email": "test2@example.com"} + + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 200 + assert response.json()["email"] == "test2@example.com" + + +@override_settings(LOAD_E2E_URLS=True) +def test_api_e2e_user_auth_email_required(): + """Email is required.""" + reload_urls() + client = APIClient() + + response = client.get("/api/v1.0/users/me/") + assert response.status_code == 401 + + response = client.post("/api/v1.0/e2e/user-auth/", {}) + assert response.status_code == 400 + assert response.json() == { + "type": "validation_error", + "errors": [ + {"code": "required", "detail": "This field is required.", "attr": "email"} + ], + } diff --git a/src/backend/e2e/urls.py b/src/backend/e2e/urls.py new file mode 100644 index 0000000..997a51e --- /dev/null +++ b/src/backend/e2e/urls.py @@ -0,0 +1,26 @@ +"""URL configuration for the e2e app.""" + +from django.conf import settings +from django.urls import include, path + +from rest_framework.routers import DefaultRouter + +from e2e import viewsets + +user_auth_router = DefaultRouter() +user_auth_router.register( + "user-auth", + viewsets.UserAuthViewSet, + basename="user-auth", +) + +urlpatterns = [ + path( + f"api/{settings.API_VERSION}/e2e/", + include( + [ + *user_auth_router.urls, + ] + ), + ), +] diff --git a/src/backend/e2e/utils.py b/src/backend/e2e/utils.py new file mode 100644 index 0000000..60d3c40 --- /dev/null +++ b/src/backend/e2e/utils.py @@ -0,0 +1,11 @@ +"""E2E utils.""" + +from core import factories, models + + +def get_or_create_e2e_user(email): + """Get or create an E2E user.""" + user = models.User.objects.filter(email=email).first() + if not user: + user = factories.UserFactory(email=email, sub=None, language="en-us") + return user diff --git a/src/backend/e2e/viewsets.py b/src/backend/e2e/viewsets.py new file mode 100644 index 0000000..6150242 --- /dev/null +++ b/src/backend/e2e/viewsets.py @@ -0,0 +1,40 @@ +"""Viewsets for the e2e app.""" + +from django.contrib.auth import login + +import rest_framework as drf +from rest_framework import response as drf_response +from rest_framework import status +from rest_framework.permissions import AllowAny + +from core import models + +from e2e.serializers import E2EAuthSerializer + + +class UserAuthViewSet(drf.viewsets.ViewSet): + """Viewset to handle user authentication""" + + permission_classes = [AllowAny] + authentication_classes = [] + + def create(self, request): + """ + POST /api/v1.0/e2e/user-auth/ + Create a user with the given email if it doesn't exist and log them in + """ + serializer = E2EAuthSerializer(data=request.data) + serializer.is_valid(raise_exception=True) + + # Create user if doesn't exist + user = models.User.objects.filter( + email=serializer.validated_data["email"] + ).first() + if not user: + user = models.User(email=serializer.validated_data["email"]) + user.set_unusable_password() + user.save() + + login(request, user, "django.contrib.auth.backends.ModelBackend") + + return drf_response.Response({"email": user.email}, status=status.HTTP_200_OK) diff --git a/src/backend/entrypoint b/src/backend/entrypoint new file mode 100755 index 0000000..5ff4aa1 --- /dev/null +++ b/src/backend/entrypoint @@ -0,0 +1,35 @@ +#!/bin/sh +# +# The container user (see USER in the Dockerfile) is an un-privileged user that +# does not exists and is not created during the build phase (see Dockerfile). +# Hence, we use this entrypoint to wrap commands that will be run in the +# container to create an entry for this user in the /etc/passwd file. +# +# The following environment variables may be passed to the container to +# customize running user account: +# +# * USER_NAME: container user name (default: default) +# * HOME : container user home directory (default: none) +# +# To pass environment variables, you can either use the -e option of the docker run command: +# +# docker run --rm -e USER_NAME=foo -e HOME='/home/foo' calendars-backend:latest python manage.py migrate +# +# or define new variables in an environment file to use with docker or docker compose: +# +# # env.d/production +# USER_NAME=foo +# HOME=/home/foo +# +# docker run --rm --env-file env.d/production calendars-backend:latest python manage.py migrate +# + +echo "🐳(entrypoint) creating user running in the container..." +if ! whoami > /dev/null 2>&1; then + if [ -w /etc/passwd ]; then + echo "${USER_NAME:-default}:x:$(id -u):$(id -g):${USER_NAME:-default} user:${HOME}:/sbin/nologin" >> /etc/passwd + fi +fi + +echo "🐳(entrypoint) running your command: ${*}" +exec "$@" diff --git a/src/backend/gunicorn.conf.py b/src/backend/gunicorn.conf.py new file mode 100644 index 0000000..dd33428 --- /dev/null +++ b/src/backend/gunicorn.conf.py @@ -0,0 +1,16 @@ +# Gunicorn-django settings +bind = ["0.0.0.0:8000"] +name = "calendars" +python_path = "/app" + +# Run +graceful_timeout = 90 +timeout = 90 +workers = 3 + +# Logging +# Using '-' for the access log file makes gunicorn log accesses to stdout +accesslog = "-" +# Using '-' for the error log file makes gunicorn log errors to stderr +errorlog = "-" +loglevel = "info" diff --git a/src/backend/locale/de_DE/LC_MESSAGES/django.po b/src/backend/locale/de_DE/LC_MESSAGES/django.po new file mode 100644 index 0000000..2308ef9 --- /dev/null +++ b/src/backend/locale/de_DE/LC_MESSAGES/django.po @@ -0,0 +1,455 @@ +msgid "" +msgstr "" +"Project-Id-Version: lasuite-docs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-19 15:10+0000\n" +"PO-Revision-Date: 2025-01-27 09:27\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de_DE\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: lasuite-docs\n" +"X-Crowdin-Project-ID: 754523\n" +"X-Crowdin-Language: de\n" +"X-Crowdin-File: backend-calendars.pot\n" +"X-Crowdin-File-ID: 18\n" + +#: core/admin.py:26 +msgid "Personal info" +msgstr "Persönliche Daten" + +#: core/admin.py:39 core/admin.py:119 +msgid "Permissions" +msgstr "Berechtigungen" + +#: core/admin.py:51 +msgid "Important dates" +msgstr "Wichtige Daten" + +#: core/admin.py:129 +msgid "Tree structure" +msgstr "" + +#: core/api/filters.py:16 +msgid "Title" +msgstr "Titel" + +#: core/api/filters.py:28 +msgid "Creator is me" +msgstr "Ersteller bin ich" + +#: core/api/filters.py:31 +msgid "Favorite" +msgstr "Favorit" + +#: core/api/serializers.py:304 +msgid "An item with this title already exists in the current path." +msgstr "" + +#: core/api/serializers.py:397 +msgid "This field is required for files." +msgstr "" + +#: core/api/serializers.py:409 +msgid "This field is required for folders." +msgstr "" + +#: core/models.py:53 core/models.py:60 +msgid "Reader" +msgstr "Lesen" + +#: core/models.py:54 core/models.py:61 +msgid "Editor" +msgstr "Bearbeiten" + +#: core/models.py:62 +msgid "Administrator" +msgstr "" + +#: core/models.py:63 +msgid "Owner" +msgstr "Besitzer" + +#: core/models.py:74 +msgid "Restricted" +msgstr "Beschränkt" + +#: core/models.py:78 +msgid "Authenticated" +msgstr "Authentifiziert" + +#: core/models.py:80 +msgid "Public" +msgstr "Öffentlich" + +#: core/models.py:86 +msgid "Folder" +msgstr "" + +#: core/models.py:87 +msgid "File" +msgstr "" + +#: core/models.py:93 +msgid "Pending" +msgstr "" + +#: core/models.py:94 +msgid "Uploaded" +msgstr "" + +#: core/models.py:116 +msgid "id" +msgstr "" + +#: core/models.py:117 +msgid "primary key for the record as UUID" +msgstr "" + +#: core/models.py:123 +msgid "created on" +msgstr "Erstellt" + +#: core/models.py:124 +msgid "date and time at which a record was created" +msgstr "Datum und Uhrzeit, an dem ein Datensatz erstellt wurde" + +#: core/models.py:129 +msgid "updated on" +msgstr "Aktualisiert" + +#: core/models.py:130 +msgid "date and time at which a record was last updated" +msgstr "Datum und Uhrzeit, an dem zuletzt aktualisiert wurde" + +#: core/models.py:166 +msgid "" +"We couldn't find a user with this sub but the email is already associated " +"with a registered user." +msgstr "" + +#: core/models.py:179 +msgid "" +"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/" +"_/: characters." +msgstr "" +"Geben Sie eine gültige Unterseite ein. Dieser Wert darf nur Buchstaben, " +"Zahlen und die @/./+/-/_/: Zeichen enthalten." + +#: core/models.py:185 +msgid "sub" +msgstr "unter" + +#: core/models.py:187 +msgid "" +"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: " +"characters only." +msgstr "" +"Erforderlich. 255 Zeichen oder weniger. Buchstaben, Zahlen und die Zeichen " +"@/./+/-/_/:" + +#: core/models.py:196 +msgid "full name" +msgstr "Name" + +#: core/models.py:197 +msgid "short name" +msgstr "Kurzbezeichnung" + +#: core/models.py:199 +msgid "identity email address" +msgstr "Identitäts-E-Mail-Adresse" + +#: core/models.py:204 +msgid "admin email address" +msgstr "Admin E-Mail-Adresse" + +#: core/models.py:211 +msgid "language" +msgstr "Sprache" + +#: core/models.py:212 +msgid "The language in which the user wants to see the interface." +msgstr "Die Sprache, in der der Benutzer die Benutzeroberfläche sehen möchte." + +#: core/models.py:218 +msgid "The timezone in which the user wants to see times." +msgstr "Die Zeitzone, in der der Nutzer Zeiten sehen möchte." + +#: core/models.py:221 +msgid "device" +msgstr "Gerät" + +#: core/models.py:223 +msgid "Whether the user is a device or a real user." +msgstr "Ob der Benutzer ein Gerät oder ein echter Benutzer ist." + +#: core/models.py:226 +msgid "staff status" +msgstr "Status des Teammitgliedes" + +#: core/models.py:228 +msgid "Whether the user can log into this admin site." +msgstr "Gibt an, ob der Benutzer sich in diese Admin-Seite einloggen kann." + +#: core/models.py:231 +msgid "active" +msgstr "aktiviert" + +#: core/models.py:234 +msgid "" +"Whether this user should be treated as active. Unselect this instead of " +"deleting accounts." +msgstr "" +"Ob dieser Benutzer als aktiviert behandelt werden soll. Deaktivieren Sie " +"diese Option, anstatt Konten zu löschen." + +#: core/models.py:246 +msgid "user" +msgstr "Benutzer" + +#: core/models.py:247 +msgid "users" +msgstr "Benutzer" + +#: core/models.py:269 +msgid "Workspace" +msgstr "" + +#: core/models.py:457 +msgid "Only folders can have children." +msgstr "" + +#: core/models.py:470 +#, fuzzy +#| msgid "This team is already in this item." +msgid "title already exists in this folder." +msgstr "Dieses Team befindet sich bereits in diesem Dokument." + +#: core/models.py:504 +msgid "title" +msgstr "Titel" + +#: core/models.py:549 +msgid "Item" +msgstr "" + +#: core/models.py:550 +#, fuzzy +#| msgid "items" +msgid "Items" +msgstr "Dokumente" + +#: core/models.py:815 +#, fuzzy, python-brace-format +#| msgid "{name} shared a item with you!" +msgid "{name} shared an item with you!" +msgstr "{name} hat ein Dokument mit Ihnen geteilt!" + +#: core/models.py:817 +#, python-brace-format +msgid "{name} invited you with the role \"{role}\" on the following item:" +msgstr "" +"{name} hat Sie mit der Rolle \"{role}\" zu folgendem Dokument eingeladen:" + +#: core/models.py:820 +#, fuzzy, python-brace-format +#| msgid "{name} shared a item with you: {title}" +msgid "{name} shared an item with you: {title}" +msgstr "{name} hat ein Dokument mit Ihnen geteilt: {title}" + +#: core/models.py:872 +#, fuzzy +#| msgid "This team is already in this template." +msgid "This item is already hard deleted." +msgstr "Dieses Team ist bereits in diesem Template." + +#: core/models.py:882 +msgid "To hard delete an item, it must first be soft deleted." +msgstr "" + +#: core/models.py:902 +#, fuzzy +#| msgid "This team is already in this template." +msgid "This item is not deleted." +msgstr "Dieses Team ist bereits in diesem Template." + +#: core/models.py:918 +msgid "This item was permanently deleted and cannot be restored." +msgstr "" + +#: core/models.py:968 +msgid "Only folders can be targeted when moving an item" +msgstr "" + +#: core/models.py:1021 +#, fuzzy +#| msgid "item/user link trace" +msgid "Item/user link trace" +msgstr "Dokument/Benutzer Linkverfolgung" + +#: core/models.py:1022 +#, fuzzy +#| msgid "item/user link traces" +msgid "Item/user link traces" +msgstr "Dokument/Benutzer Linkverfolgung" + +#: core/models.py:1028 +msgid "A link trace already exists for this item/user." +msgstr "" + +#: core/models.py:1051 +#, fuzzy +#| msgid "item favorite" +msgid "Item favorite" +msgstr "Dokumentenfavorit" + +#: core/models.py:1052 +#, fuzzy +#| msgid "item favorites" +msgid "Item favorites" +msgstr "Dokumentfavoriten" + +#: core/models.py:1058 +msgid "" +"This item is already targeted by a favorite relation instance for the same " +"user." +msgstr "" +"Dieses Dokument ist bereits durch den gleichen Benutzer favorisiert worden." + +#: core/models.py:1080 +#, fuzzy +#| msgid "item/user relation" +msgid "Item/user relation" +msgstr "Dokument/Benutzerbeziehung" + +#: core/models.py:1081 +#, fuzzy +#| msgid "item/user relations" +msgid "Item/user relations" +msgstr "Dokument/Benutzerbeziehungen" + +#: core/models.py:1087 +msgid "This user is already in this item." +msgstr "Dieser Benutzer befindet sich bereits in diesem Dokument." + +#: core/models.py:1093 +msgid "This team is already in this item." +msgstr "Dieses Team befindet sich bereits in diesem Dokument." + +#: core/models.py:1099 +msgid "Either user or team must be set, not both." +msgstr "Benutzer oder Team müssen gesetzt werden, nicht beides." + +#: core/models.py:1126 +msgid "email address" +msgstr "E-Mail-Adresse" + +#: core/models.py:1145 +#, fuzzy +#| msgid "item invitation" +msgid "Item invitation" +msgstr "Einladung zum Dokument" + +#: core/models.py:1146 +#, fuzzy +#| msgid "item invitations" +msgid "Item invitations" +msgstr "Dokumenteinladungen" + +#: core/templates/mail/html/invitation.html:162 +#: core/templates/mail/text/invitation.txt:3 +msgid "Logo email" +msgstr "" + +#: core/templates/mail/html/invitation.html:209 +#: core/templates/mail/text/invitation.txt:10 +msgid "Open" +msgstr "" + +#: core/templates/mail/html/invitation.html:226 +#: core/templates/mail/text/invitation.txt:14 +msgid "" +" Calendars, your new essential tool for organizing, sharing and collaborating as " +"a team. " +msgstr "" + +#: core/templates/mail/html/invitation.html:233 +#: core/templates/mail/text/invitation.txt:16 +#, python-format +msgid " Brought to you by %(brandname)s " +msgstr "" + +#: calendars/settings.py:250 +msgid "English" +msgstr "Englisch" + +#: calendars/settings.py:251 +msgid "French" +msgstr "Französisch" + +#: calendars/settings.py:252 +msgid "German" +msgstr "Deutsch" + +#~ msgid "Invalid response format or token verification failed" +#~ msgstr "Ungültiges Antwortformat oder Token-Verifizierung fehlgeschlagen" + +#~ msgid "User account is disabled" +#~ msgstr "Benutzerkonto ist deaktiviert" + +#, fuzzy +#~| msgid "Untitled item" +#~ msgid "Untitled Item" +#~ msgstr "Unbenanntes Dokument" + +#~ msgid "This email is already associated to a registered user." +#~ msgstr "Diese E-Mail ist bereits einem registrierten Benutzer zugeordnet." + +#~ msgid "A new item was created on your behalf!" +#~ msgstr "Ein neues Dokument wurde in Ihrem Namen erstellt!" + +#~ msgid "You have been granted ownership of a new item:" +#~ msgstr "Sie sind Besitzer eines neuen Dokuments:" + +#~ msgid "Body" +#~ msgstr "Inhalt" + +#~ msgid "Body type" +#~ msgstr "Typ" + +#~ msgid "item" +#~ msgstr "Dokument" + +#~ msgid "description" +#~ msgstr "Beschreibung" + +#~ msgid "code" +#~ msgstr "Code" + +#~ msgid "css" +#~ msgstr "CSS" + +#~ msgid "public" +#~ msgstr "öffentlich" + +#~ msgid "Whether this template is public for anyone to use." +#~ msgstr "Ob diese Vorlage für jedermann öffentlich ist." + +#~ msgid "Template" +#~ msgstr "Vorlage" + +#~ msgid "Templates" +#~ msgstr "Vorlagen" + +#~ msgid "Template/user relation" +#~ msgstr "Vorlage/Benutzer-Beziehung" + +#~ msgid "Template/user relations" +#~ msgstr "Vorlage/Benutzerbeziehungen" + +#~ msgid "This user is already in this template." +#~ msgstr "Dieser Benutzer ist bereits in dieser Vorlage." diff --git a/src/backend/locale/en_US/LC_MESSAGES/django.po b/src/backend/locale/en_US/LC_MESSAGES/django.po new file mode 100644 index 0000000..e4d70c6 --- /dev/null +++ b/src/backend/locale/en_US/LC_MESSAGES/django.po @@ -0,0 +1,362 @@ +msgid "" +msgstr "" +"Project-Id-Version: lasuite-docs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-19 15:10+0000\n" +"PO-Revision-Date: 2025-01-27 09:27\n" +"Last-Translator: \n" +"Language-Team: English\n" +"Language: en_US\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: lasuite-docs\n" +"X-Crowdin-Project-ID: 754523\n" +"X-Crowdin-Language: en\n" +"X-Crowdin-File: backend-calendars.pot\n" +"X-Crowdin-File-ID: 18\n" + +#: core/admin.py:26 +msgid "Personal info" +msgstr "" + +#: core/admin.py:39 core/admin.py:119 +msgid "Permissions" +msgstr "" + +#: core/admin.py:51 +msgid "Important dates" +msgstr "" + +#: core/admin.py:129 +msgid "Tree structure" +msgstr "" + +#: core/api/filters.py:16 +msgid "Title" +msgstr "" + +#: core/api/filters.py:28 +msgid "Creator is me" +msgstr "" + +#: core/api/filters.py:31 +msgid "Favorite" +msgstr "" + +#: core/api/serializers.py:304 +msgid "An item with this title already exists in the current path." +msgstr "" + +#: core/api/serializers.py:397 +msgid "This field is required for files." +msgstr "" + +#: core/api/serializers.py:409 +msgid "This field is required for folders." +msgstr "" + +#: core/models.py:53 core/models.py:60 +msgid "Reader" +msgstr "" + +#: core/models.py:54 core/models.py:61 +msgid "Editor" +msgstr "" + +#: core/models.py:62 +msgid "Administrator" +msgstr "" + +#: core/models.py:63 +msgid "Owner" +msgstr "" + +#: core/models.py:74 +msgid "Restricted" +msgstr "" + +#: core/models.py:78 +msgid "Authenticated" +msgstr "" + +#: core/models.py:80 +msgid "Public" +msgstr "" + +#: core/models.py:86 +msgid "Folder" +msgstr "" + +#: core/models.py:87 +msgid "File" +msgstr "" + +#: core/models.py:93 +msgid "Pending" +msgstr "" + +#: core/models.py:94 +msgid "Uploaded" +msgstr "" + +#: core/models.py:116 +msgid "id" +msgstr "" + +#: core/models.py:117 +msgid "primary key for the record as UUID" +msgstr "" + +#: core/models.py:123 +msgid "created on" +msgstr "" + +#: core/models.py:124 +msgid "date and time at which a record was created" +msgstr "" + +#: core/models.py:129 +msgid "updated on" +msgstr "" + +#: core/models.py:130 +msgid "date and time at which a record was last updated" +msgstr "" + +#: core/models.py:166 +msgid "" +"We couldn't find a user with this sub but the email is already associated " +"with a registered user." +msgstr "" + +#: core/models.py:179 +msgid "" +"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/" +"_/: characters." +msgstr "" + +#: core/models.py:185 +msgid "sub" +msgstr "" + +#: core/models.py:187 +msgid "" +"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: " +"characters only." +msgstr "" + +#: core/models.py:196 +msgid "full name" +msgstr "" + +#: core/models.py:197 +msgid "short name" +msgstr "" + +#: core/models.py:199 +msgid "identity email address" +msgstr "" + +#: core/models.py:204 +msgid "admin email address" +msgstr "" + +#: core/models.py:211 +msgid "language" +msgstr "" + +#: core/models.py:212 +msgid "The language in which the user wants to see the interface." +msgstr "" + +#: core/models.py:218 +msgid "The timezone in which the user wants to see times." +msgstr "" + +#: core/models.py:221 +msgid "device" +msgstr "" + +#: core/models.py:223 +msgid "Whether the user is a device or a real user." +msgstr "" + +#: core/models.py:226 +msgid "staff status" +msgstr "" + +#: core/models.py:228 +msgid "Whether the user can log into this admin site." +msgstr "" + +#: core/models.py:231 +msgid "active" +msgstr "" + +#: core/models.py:234 +msgid "" +"Whether this user should be treated as active. Unselect this instead of " +"deleting accounts." +msgstr "" + +#: core/models.py:246 +msgid "user" +msgstr "" + +#: core/models.py:247 +msgid "users" +msgstr "" + +#: core/models.py:269 +msgid "Workspace" +msgstr "" + +#: core/models.py:457 +msgid "Only folders can have children." +msgstr "" + +#: core/models.py:470 +msgid "title already exists in this folder." +msgstr "" + +#: core/models.py:504 +msgid "title" +msgstr "" + +#: core/models.py:549 +msgid "Item" +msgstr "" + +#: core/models.py:550 +msgid "Items" +msgstr "" + +#: core/models.py:815 +#, python-brace-format +msgid "{name} shared an item with you!" +msgstr "" + +#: core/models.py:817 +#, python-brace-format +msgid "{name} invited you with the role \"{role}\" on the following item:" +msgstr "" + +#: core/models.py:820 +#, python-brace-format +msgid "{name} shared an item with you: {title}" +msgstr "" + +#: core/models.py:872 +msgid "This item is already hard deleted." +msgstr "" + +#: core/models.py:882 +msgid "To hard delete an item, it must first be soft deleted." +msgstr "" + +#: core/models.py:902 +msgid "This item is not deleted." +msgstr "" + +#: core/models.py:918 +msgid "This item was permanently deleted and cannot be restored." +msgstr "" + +#: core/models.py:968 +msgid "Only folders can be targeted when moving an item" +msgstr "" + +#: core/models.py:1021 +msgid "Item/user link trace" +msgstr "" + +#: core/models.py:1022 +msgid "Item/user link traces" +msgstr "" + +#: core/models.py:1028 +msgid "A link trace already exists for this item/user." +msgstr "" + +#: core/models.py:1051 +msgid "Item favorite" +msgstr "" + +#: core/models.py:1052 +msgid "Item favorites" +msgstr "" + +#: core/models.py:1058 +msgid "" +"This item is already targeted by a favorite relation instance for the same " +"user." +msgstr "" + +#: core/models.py:1080 +msgid "Item/user relation" +msgstr "" + +#: core/models.py:1081 +msgid "Item/user relations" +msgstr "" + +#: core/models.py:1087 +msgid "This user is already in this item." +msgstr "" + +#: core/models.py:1093 +msgid "This team is already in this item." +msgstr "" + +#: core/models.py:1099 +msgid "Either user or team must be set, not both." +msgstr "" + +#: core/models.py:1126 +msgid "email address" +msgstr "" + +#: core/models.py:1145 +msgid "Item invitation" +msgstr "" + +#: core/models.py:1146 +msgid "Item invitations" +msgstr "" + +#: core/templates/mail/html/invitation.html:162 +#: core/templates/mail/text/invitation.txt:3 +msgid "Logo email" +msgstr "" + +#: core/templates/mail/html/invitation.html:209 +#: core/templates/mail/text/invitation.txt:10 +msgid "Open" +msgstr "" + +#: core/templates/mail/html/invitation.html:226 +#: core/templates/mail/text/invitation.txt:14 +msgid "" +" Calendars, your new essential tool for organizing, sharing and collaborating as " +"a team. " +msgstr "" + +#: core/templates/mail/html/invitation.html:233 +#: core/templates/mail/text/invitation.txt:16 +#, python-format +msgid " Brought to you by %(brandname)s " +msgstr "" + +#: calendars/settings.py:250 +msgid "English" +msgstr "" + +#: calendars/settings.py:251 +msgid "French" +msgstr "" + +#: calendars/settings.py:252 +msgid "German" +msgstr "" diff --git a/src/backend/locale/fr_FR/LC_MESSAGES/django.po b/src/backend/locale/fr_FR/LC_MESSAGES/django.po new file mode 100644 index 0000000..88ce6cb --- /dev/null +++ b/src/backend/locale/fr_FR/LC_MESSAGES/django.po @@ -0,0 +1,371 @@ +msgid "" +msgstr "" +"Project-Id-Version: lasuite-docs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-19 15:10+0000\n" +"PO-Revision-Date: 2025-01-27 09:27\n" +"Last-Translator: \n" +"Language-Team: French\n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Crowdin-Project: lasuite-docs\n" +"X-Crowdin-Project-ID: 754523\n" +"X-Crowdin-Language: fr\n" +"X-Crowdin-File: backend-calendars.pot\n" +"X-Crowdin-File-ID: 18\n" + +#: core/admin.py:26 +msgid "Personal info" +msgstr "Infos Personnelles" + +#: core/admin.py:39 core/admin.py:119 +msgid "Permissions" +msgstr "" + +#: core/admin.py:51 +msgid "Important dates" +msgstr "Dates importantes" + +#: core/admin.py:129 +msgid "Tree structure" +msgstr "" + +#: core/api/filters.py:16 +msgid "Title" +msgstr "" + +#: core/api/filters.py:28 +msgid "Creator is me" +msgstr "" + +#: core/api/filters.py:31 +msgid "Favorite" +msgstr "" + +#: core/api/serializers.py:304 +msgid "An item with this title already exists in the current path." +msgstr "" + +#: core/api/serializers.py:397 +msgid "This field is required for files." +msgstr "" + +#: core/api/serializers.py:409 +msgid "This field is required for folders." +msgstr "" + +#: core/models.py:53 core/models.py:60 +msgid "Reader" +msgstr "Lecteur" + +#: core/models.py:54 core/models.py:61 +msgid "Editor" +msgstr "Éditeur" + +#: core/models.py:62 +msgid "Administrator" +msgstr "Administrateur" + +#: core/models.py:63 +msgid "Owner" +msgstr "Propriétaire" + +#: core/models.py:74 +msgid "Restricted" +msgstr "Restreint" + +#: core/models.py:78 +msgid "Authenticated" +msgstr "Authentifié" + +#: core/models.py:80 +msgid "Public" +msgstr "" + +#: core/models.py:86 +msgid "Folder" +msgstr "" + +#: core/models.py:87 +msgid "File" +msgstr "" + +#: core/models.py:93 +msgid "Pending" +msgstr "" + +#: core/models.py:94 +msgid "Uploaded" +msgstr "" + +#: core/models.py:116 +msgid "id" +msgstr "" + +#: core/models.py:117 +msgid "primary key for the record as UUID" +msgstr "" + +#: core/models.py:123 +msgid "created on" +msgstr "" + +#: core/models.py:124 +msgid "date and time at which a record was created" +msgstr "" + +#: core/models.py:129 +msgid "updated on" +msgstr "" + +#: core/models.py:130 +msgid "date and time at which a record was last updated" +msgstr "" + +#: core/models.py:166 +msgid "" +"We couldn't find a user with this sub but the email is already associated " +"with a registered user." +msgstr "" + +#: core/models.py:179 +msgid "" +"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/" +"_/: characters." +msgstr "" + +#: core/models.py:185 +msgid "sub" +msgstr "" + +#: core/models.py:187 +msgid "" +"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: " +"characters only." +msgstr "" + +#: core/models.py:196 +msgid "full name" +msgstr "" + +#: core/models.py:197 +msgid "short name" +msgstr "" + +#: core/models.py:199 +msgid "identity email address" +msgstr "" + +#: core/models.py:204 +msgid "admin email address" +msgstr "" + +#: core/models.py:211 +msgid "language" +msgstr "" + +#: core/models.py:212 +msgid "The language in which the user wants to see the interface." +msgstr "" + +#: core/models.py:218 +msgid "The timezone in which the user wants to see times." +msgstr "" + +#: core/models.py:221 +msgid "device" +msgstr "" + +#: core/models.py:223 +msgid "Whether the user is a device or a real user." +msgstr "" + +#: core/models.py:226 +msgid "staff status" +msgstr "" + +#: core/models.py:228 +msgid "Whether the user can log into this admin site." +msgstr "" + +#: core/models.py:231 +msgid "active" +msgstr "" + +#: core/models.py:234 +msgid "" +"Whether this user should be treated as active. Unselect this instead of " +"deleting accounts." +msgstr "" + +#: core/models.py:246 +msgid "user" +msgstr "" + +#: core/models.py:247 +msgid "users" +msgstr "" + +#: core/models.py:269 +msgid "Workspace" +msgstr "" + +#: core/models.py:457 +msgid "Only folders can have children." +msgstr "" + +#: core/models.py:470 +msgid "title already exists in this folder." +msgstr "" + +#: core/models.py:504 +msgid "title" +msgstr "" + +#: core/models.py:549 +msgid "Item" +msgstr "" + +#: core/models.py:550 +msgid "Items" +msgstr "" + +#: core/models.py:815 +#, python-brace-format +msgid "{name} shared an item with you!" +msgstr "{name} a partagé un item avec vous!" + +#: core/models.py:817 +#, python-brace-format +msgid "{name} invited you with the role \"{role}\" on the following item:" +msgstr "{name} vous a invité avec le rôle \"{role}\" sur le item suivant:" + +#: core/models.py:820 +#, python-brace-format +#| msgid "{name} shared an item with you: {title}" +msgid "{name} shared an item with you: {title}" +msgstr "{name} a partagé un item avec vous: {title}" + +#: core/models.py:872 +msgid "This item is already hard deleted." +msgstr "" + +#: core/models.py:882 +msgid "To hard delete an item, it must first be soft deleted." +msgstr "" + +#: core/models.py:902 +msgid "This item is not deleted." +msgstr "" + +#: core/models.py:918 +msgid "This item was permanently deleted and cannot be restored." +msgstr "" + +#: core/models.py:968 +msgid "Only folders can be targeted when moving an item" +msgstr "" + +#: core/models.py:1021 +msgid "Item/user link trace" +msgstr "" + +#: core/models.py:1022 +msgid "Item/user link traces" +msgstr "" + +#: core/models.py:1028 +msgid "A link trace already exists for this item/user." +msgstr "" + +#: core/models.py:1051 +msgid "Item favorite" +msgstr "" + +#: core/models.py:1052 +msgid "Item favorites" +msgstr "" + +#: core/models.py:1058 +msgid "" +"This item is already targeted by a favorite relation instance for the same " +"user." +msgstr "" + +#: core/models.py:1080 +msgid "Item/user relation" +msgstr "" + +#: core/models.py:1081 +msgid "Item/user relations" +msgstr "" + +#: core/models.py:1087 +msgid "This user is already in this item." +msgstr "" + +#: core/models.py:1093 +msgid "This team is already in this item." +msgstr "" + +#: core/models.py:1099 +msgid "Either user or team must be set, not both." +msgstr "" + +#: core/models.py:1126 +msgid "email address" +msgstr "" + +#: core/models.py:1145 +msgid "Item invitation" +msgstr "" + +#: core/models.py:1146 +msgid "Item invitations" +msgstr "" + +#: core/templates/mail/html/invitation.html:162 +#: core/templates/mail/text/invitation.txt:3 +msgid "Logo email" +msgstr "" + +#: core/templates/mail/html/invitation.html:209 +#: core/templates/mail/text/invitation.txt:10 +msgid "Open" +msgstr "Ouvrir" + +#: core/templates/mail/html/invitation.html:226 +#: core/templates/mail/text/invitation.txt:14 +msgid "" +" Calendars, your new essential tool for organizing, sharing and collaborating as " +"a team. " +msgstr "" +"Fichiers, votre outil essentiel pour organiser, partager et collaborer en " +"équipe." + +#: core/templates/mail/html/invitation.html:233 +#: core/templates/mail/text/invitation.txt:16 +#, python-format +msgid " Brought to you by %(brandname)s " +msgstr " Proposé par %(brandname)s " + +#: calendars/settings.py:250 +msgid "English" +msgstr "" + +#: calendars/settings.py:251 +msgid "French" +msgstr "" + +#: calendars/settings.py:252 +msgid "German" +msgstr "" + +#~ msgid "A new item was created on your behalf!" +#~ msgstr "Un nouveau item a été créé pour vous !" + +#~ msgid "You have been granted ownership of a new item:" +#~ msgstr "Vous avez été déclaré propriétaire d'un nouveau item :" diff --git a/src/backend/locale/nl_NL/LC_MESSAGES/django.po b/src/backend/locale/nl_NL/LC_MESSAGES/django.po new file mode 100644 index 0000000..48e39e2 --- /dev/null +++ b/src/backend/locale/nl_NL/LC_MESSAGES/django.po @@ -0,0 +1,369 @@ +msgid "" +msgstr "" +"Project-Id-Version: lasuite-docs\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-05-19 15:10+0000\n" +"PO-Revision-Date: 2025-01-27 09:27\n" +"Last-Translator: \n" +"Language-Team: Dutch\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Crowdin-Project: lasuite-docs\n" +"X-Crowdin-Project-ID: 754523\n" +"X-Crowdin-Language: nl\n" +"X-Crowdin-File: backend-calendars.pot\n" +"X-Crowdin-File-ID: 18\n" + +#: core/admin.py:26 +msgid "Personal info" +msgstr "Persoonlijke gegevens" + +#: core/admin.py:39 core/admin.py:119 +msgid "Permissions" +msgstr "Machtigingen" + +#: core/admin.py:51 +msgid "Important dates" +msgstr "Belangrijke data" + +#: core/admin.py:129 +msgid "Tree structure" +msgstr "Boomstructuur" + +#: core/api/filters.py:16 +msgid "Title" +msgstr "Titel" + +#: core/api/filters.py:28 +msgid "Creator is me" +msgstr "Ik ben eigenaar" + +#: core/api/filters.py:31 +msgid "Favorite" +msgstr "Favoriet" + +#: core/api/serializers.py:304 +msgid "An item with this title already exists in the current path." +msgstr "Er bestaat al een item met deze titel in het huidige pad." + +#: core/api/serializers.py:397 +msgid "This field is required for files." +msgstr "Dit veld is verplicht voor bestanden" + +#: core/api/serializers.py:409 +msgid "This field is required for folders." +msgstr "Dit veld is verplicht voor mappen." + +#: core/models.py:53 core/models.py:60 +msgid "Reader" +msgstr "Lezer" + +#: core/models.py:54 core/models.py:61 +msgid "Editor" +msgstr "Redacteur" + +#: core/models.py:62 +msgid "Administrator" +msgstr "Beheerder" + +#: core/models.py:63 +msgid "Owner" +msgstr "Eigenaar" + +#: core/models.py:74 +msgid "Restricted" +msgstr "Beperkt" + +#: core/models.py:78 +msgid "Authenticated" +msgstr "Ingelogd" + +#: core/models.py:80 +msgid "Public" +msgstr "Openbaar" + +#: core/models.py:86 +msgid "Folder" +msgstr "Map" + +#: core/models.py:87 +msgid "File" +msgstr "Bestand" + +#: core/models.py:93 +msgid "Pending" +msgstr "In afwachting" + +#: core/models.py:94 +msgid "Uploaded" +msgstr "Geüpload" + +#: core/models.py:116 +msgid "id" +msgstr "id" + +#: core/models.py:117 +msgid "primary key for the record as UUID" +msgstr "primaire sleutel voor het record als UUID" + +#: core/models.py:123 +msgid "created on" +msgstr "gecreëerd op" + +#: core/models.py:124 +msgid "date and time at which a record was created" +msgstr "datum en tijd waarop een record is gemaakt" + +#: core/models.py:129 +msgid "updated on" +msgstr "bijgewerkt op" + +#: core/models.py:130 +msgid "date and time at which a record was last updated" +msgstr "datum en tijd waarop een record voor het laatst is bijgewerkt" + +#: core/models.py:166 +msgid "" +"We couldn't find a user with this sub but the email is already associated " +"with a registered user." +msgstr "We konden geen gebruiker vinden met deze id, maar het e-mailadres is al gekoppeld aan een geregistreerde gebruiker." + +#: core/models.py:179 +msgid "" +"Enter a valid sub. This value may contain only letters, numbers, and @/./+/-/" +"_/: characters." +msgstr "Voer een geldige sub in. Deze waarde mag alleen letters, cijfers en @/./+/-/_/: " +"tekens bevatten." + +#: core/models.py:185 +msgid "sub" +msgstr "id" + +#: core/models.py:187 +msgid "" +"Required. 255 characters or fewer. Letters, numbers, and @/./+/-/_/: " +"characters only." +msgstr "Verplicht. 255 tekens of minder. Alleen letters, cijfers en @/./+/-/_/: tekens." + +#: core/models.py:196 +msgid "full name" +msgstr "volledige naam" + +#: core/models.py:197 +msgid "short name" +msgstr "gebruikersnaam" + +#: core/models.py:199 +msgid "identity email address" +msgstr "identiteits e-mailadres" + +#: core/models.py:204 +msgid "admin email address" +msgstr "admin e-mailadres" + +#: core/models.py:211 +msgid "language" +msgstr "taal" + +#: core/models.py:212 +msgid "The language in which the user wants to see the interface." +msgstr "De taal waarin de gebruiker de interface wil zien." + +#: core/models.py:218 +msgid "The timezone in which the user wants to see times." +msgstr "Tijdzone waarin de gebruiker de tijd wil zien." + +#: core/models.py:221 +msgid "device" +msgstr "apparaat" + +#: core/models.py:223 +msgid "Whether the user is a device or a real user." +msgstr "Of de gebruiker een apparaat of een echte gebruiker is." + +#: core/models.py:226 +msgid "staff status" +msgstr "personeelsstatus" + +#: core/models.py:228 +msgid "Whether the user can log into this admin site." +msgstr "Of de gebruiker kan inloggen op deze beheer site." + +#: core/models.py:231 +msgid "active" +msgstr "actief" + +#: core/models.py:234 +msgid "" +"Whether this user should be treated as active. Unselect this instead of " +"deleting accounts." +msgstr "Of deze gebruiker als actief moet worden behandeld. Deselecteer dit in plaats van " +"accounts te verwijderen." + +#: core/models.py:246 +msgid "user" +msgstr "gebruiker" + +#: core/models.py:247 +msgid "users" +msgstr "gebruikers" + +#: core/models.py:269 +msgid "Workspace" +msgstr "Werkruimte" + +#: core/models.py:457 +msgid "Only folders can have children." +msgstr "Alleen mappen kunnen subitems hebben." + +#: core/models.py:470 +msgid "title already exists in this folder." +msgstr "titel bestaat al in deze map." + +#: core/models.py:504 +msgid "title" +msgstr "titel" + +#: core/models.py:549 +msgid "Item" +msgstr "Item" + +#: core/models.py:550 +msgid "Items" +msgstr "Items" + +#: core/models.py:815 +#, python-brace-format +msgid "{name} shared an item with you!" +msgstr "{name} heeft een item met je gedeeld!" + +#: core/models.py:817 +#, python-brace-format +msgid "{name} invited you with the role \"{role}\" on the following item:" +msgstr "{name} heeft je uitgenodigd met de rol \"{role}\" voor het volgende item:" + +#: core/models.py:820 +#, python-brace-format +msgid "{name} shared an item with you: {title}" +msgstr "{name} heeft een item met je gedeeld: {title}" + +#: core/models.py:872 +msgid "This item is already hard deleted." +msgstr "Dit item is al permanent verwijderd." + +#: core/models.py:882 +msgid "To hard delete an item, it must first be soft deleted." +msgstr "Om een item permanent te verwijderen, moet het eerst tijdelijk worden verwijderd." + +#: core/models.py:902 +msgid "This item is not deleted." +msgstr "Dit item is niet verwijderd." + +#: core/models.py:918 +msgid "This item was permanently deleted and cannot be restored." +msgstr "Dit item is permanent verwijderd en kan niet worden hersteld." + +#: core/models.py:968 +msgid "Only folders can be targeted when moving an item" +msgstr "Alleen mappen kunnen worden geselecteerd bij het verplaatsen van een item." + +#: core/models.py:1021 +msgid "Item/user link trace" +msgstr "Item/gebruiker link " + +#: core/models.py:1022 +msgid "Item/user link traces" +msgstr "Item/gebruiker link" + +#: core/models.py:1028 +msgid "A link trace already exists for this item/user." +msgstr "Er bestaat al een link trace voor dit item/gebruiker." + +#: core/models.py:1051 +msgid "Item favorite" +msgstr "Item favoriet" + +#: core/models.py:1052 +msgid "Item favorites" +msgstr "Item favorieten" + +#: core/models.py:1058 +msgid "" +"This item is already targeted by a favorite relation instance for the same " +"user." +msgstr "Dit item is al het doel van een favorietrelatie voor dezelfde " +"gebruiker." + +#: core/models.py:1080 +msgid "Item/user relation" +msgstr "Item/gebruiker relatie" + +#: core/models.py:1081 +msgid "Item/user relations" +msgstr "Item/gebruiker relaties" + +#: core/models.py:1087 +msgid "This user is already in this item." +msgstr "Deze gebruiker bestaat al in dit item." + +#: core/models.py:1093 +msgid "This team is already in this item." +msgstr "Dit team bestaat al in dit item." + +#: core/models.py:1099 +msgid "Either user or team must be set, not both." +msgstr "Ofwel gebruiker of team moet worden ingesteld, niet beide." + +#: core/models.py:1126 +msgid "email address" +msgstr "e-mailadres" + +#: core/models.py:1145 +msgid "Item invitation" +msgstr "Item uitnodiging" + +#: core/models.py:1146 +msgid "Item invitations" +msgstr "Item uitnodigingen" + +#: core/templates/mail/html/invitation.html:162 +#: core/templates/mail/text/invitation.txt:3 +msgid "Logo email" +msgstr "Logo e-mail" + +#: core/templates/mail/html/invitation.html:209 +#: core/templates/mail/text/invitation.txt:10 +msgid "Open" +msgstr "Open" + +#: core/templates/mail/html/invitation.html:226 +#: core/templates/mail/text/invitation.txt:14 +msgid "" +" Calendars, your new essential tool for organizing, sharing and collaborating as " +"a team. " +msgstr " Calendars, jouw nieuwe essentiële tool voor het organiseren, delen en samenwerken als team" + +#: core/templates/mail/html/invitation.html:233 +#: core/templates/mail/text/invitation.txt:16 +#, python-format +msgid " Brought to you by %(brandname)s " +msgstr " Aangeboden door %(brandname)s " + +#: calendars/settings.py:250 +msgid "English" +msgstr "Engels" + +#: calendars/settings.py:251 +msgid "French" +msgstr "Frans" + +#: calendars/settings.py:252 +msgid "German" +msgstr "Duits" + +#: calendars/settings.py:253 +msgid "Dutch" +msgstr "Nederlands" diff --git a/src/backend/manage.py b/src/backend/manage.py new file mode 100644 index 0000000..c590546 --- /dev/null +++ b/src/backend/manage.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python +""" +calendars' management script. +""" + +import os +import sys + +if __name__ == "__main__": + os.environ.setdefault("DJANGO_SETTINGS_MODULE", "calendars.settings") + os.environ.setdefault("DJANGO_CONFIGURATION", "Development") + + from configurations.management import execute_from_command_line + + execute_from_command_line(sys.argv) diff --git a/src/backend/pyproject.toml b/src/backend/pyproject.toml new file mode 100644 index 0000000..7e103e8 --- /dev/null +++ b/src/backend/pyproject.toml @@ -0,0 +1,145 @@ +# +# calendar package +# +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "calendars" +version = "0.10.1" +authors = [{ "name" = "anct", "email" = "contact@suite.anct.gouv.fr" }] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Framework :: Django", + "Framework :: Django :: 5", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.13", +] +description = "A calendar application." +keywords = ["Django", "Contacts", "Templates", "RBAC"] +license = { file = "LICENSE" } +readme = "README.md" +requires-python = "~=3.13.0" +dependencies = [ + "Brotli==1.2.0", + "dj-database-url==3.0.1", + "caldav==2.2.3", + "celery[redis]==5.6.0", + "django==5.2.9", + "django-celery-beat==2.8.1", + "django-configurations==2.5.1", + "django-cors-headers==4.9.0", + "django-countries==8.2.0", + "django-filter==25.2", + "django-lasuite[all]==0.0.21", + "django-parler==2.3", + "django-redis==6.0.0", + "django-timezone-field>=5.1", + "djangorestframework==3.16.1", + "djangorestframework-api-key==3.1.0", + "drf_spectacular==0.29.0", + "drf-standardized-errors==0.15.0", + "factory_boy==3.3.3", + "gunicorn==23.0.0", + "jsonschema==4.25.1", + "mozilla-django-oidc==4.0.1", + "nested-multipart-parser==1.6.0", + "pillow>=10.0", + "psycopg[binary]==3.3.1", + "PyJWT==2.10.1", + "redis<6.0.0", + "requests==2.32.5", + "sentry-sdk==2.46.0", + "url-normalize==2.2.1", + "whitenoise==6.11.0", +] + +[project.urls] +"Bug Tracker" = "https://github.com/suitenumerique/calendars/issues/new" +"Changelog" = "https://github.com/suitenumerique/calendars/blob/main/CHANGELOG.md" +"Homepage" = "https://github.com/suitenumerique/calendars" +"Repository" = "https://github.com/suitenumerique/calendars" + +[project.optional-dependencies] +dev = [ + "django-debug-toolbar==6.1.0", + "django-extensions==4.1", + "drf-spectacular-sidecar==2025.12.1", + "freezegun==1.5.5", + "ipdb==0.13.13", + "ipython==9.7.0", + "pyfakefs==5.10.2", + "pylint-django==2.6.1", + "pylint<4.0.0", + "pytest-cov==7.0.0", + "pytest-django==4.11.1", + "pytest==9.0.1", + "pytest-icdiff==0.9", + "pytest-xdist==3.8.0", + "responses==0.25.8", + "ruff==0.14.7", + "types-requests==2.32.4.20250913", +] + +[tool.setuptools] +packages = { find = { where = ["."], exclude = ["tests"] } } +zip-safe = true + +[tool.distutils.bdist_wheel] +universal = true + +[tool.ruff] +exclude = [ + ".git", + ".venv", + "build", + "venv", + "__pycache__", + "*/migrations/*", +] +line-length = 88 + + +[tool.ruff.lint] +ignore = ["DJ001", "PLR2004"] +select = [ + "B", # flake8-bugbear + "BLE", # flake8-blind-except + "C4", # flake8-comprehensions + "DJ", # flake8-django + "I", # isort + "PLC", # pylint-convention + "PLE", # pylint-error + "PLR", # pylint-refactoring + "PLW", # pylint-warning + "RUF100", # Ruff unused-noqa + "RUF200", # Ruff check pyproject.toml + "S", # flake8-bandit + "SLF", # flake8-self + "T20", # flake8-print +] + +[tool.ruff.lint.isort] +section-order = ["future","standard-library","django","third-party","calendars","first-party","local-folder"] +sections = { calendars=["core", "caldav"], django=["django"] } +extra-standard-library = ["tomllib"] + +[tool.ruff.lint.per-file-ignores] +"**/tests/*" = ["S", "SLF"] + +[tool.pytest.ini_options] +addopts = [ + "-v", + "--cov-report", + "term-missing", + # Allow test files to have the same name in different directories. + "--import-mode=importlib", +] +python_files = [ + "test_*.py", + "tests.py", +] diff --git a/src/backend/uv.lock b/src/backend/uv.lock new file mode 100644 index 0000000..75a22da --- /dev/null +++ b/src/backend/uv.lock @@ -0,0 +1,1836 @@ +version = 1 +revision = 3 +requires-python = "==3.13.*" + +[[package]] +name = "amqp" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/fc/ec94a357dfc6683d8c86f8b4cfa5416a4c36b28052ec8260c77aca96a443/amqp-5.3.1.tar.gz", hash = "sha256:cddc00c725449522023bad949f70fff7b48f0b1ade74d170a6f10ab044739432", size = 129013, upload-time = "2024-11-12T19:55:44.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/26/99/fc813cd978842c26c82534010ea849eee9ab3a13ea2b74e95cb9c99e747b/amqp-5.3.1-py3-none-any.whl", hash = "sha256:43b3319e1b4e7d1251833a93d672b4af1e40f3d632d479b98661a95f117880a2", size = 50944, upload-time = "2024-11-12T19:55:41.782Z" }, +] + +[[package]] +name = "asgiref" +version = "3.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/b9/4db2509eabd14b4a8c71d1b24c8d5734c52b8560a7b1e1a8b56c8d25568b/asgiref-3.11.0.tar.gz", hash = "sha256:13acff32519542a1736223fb79a715acdebe24286d98e8b164a73085f40da2c4", size = 37969, upload-time = "2025-11-19T15:32:20.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/be/317c2c55b8bbec407257d45f5c8d1b6867abc76d12043f2d3d58c538a4ea/asgiref-3.11.0-py3-none-any.whl", hash = "sha256:1db9021efadb0d9512ce8ffaf72fcef601c7b73a8807a1bb2ef143dc6b14846d", size = 24096, upload-time = "2025-11-19T15:32:19.004Z" }, +] + +[[package]] +name = "astroid" +version = "3.3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/0f/3b8fdc946b4d9cc8cc1e8af42c4e409468c84441b933d037e101b3d72d86/astroid-3.3.11-py3-none-any.whl", hash = "sha256:54c760ae8322ece1abd213057c4b5bba7c49818853fc901ef09719a60dbf9dec", size = 275612, upload-time = "2025-07-13T18:04:21.07Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/be/a5/8e3f9b6771b0b408517c82d97aed8f2036509bc247d46114925e32fe33f0/asttokens-3.0.1.tar.gz", hash = "sha256:71a4ee5de0bde6a31d64f6b13f2293ac190344478f081c3d1bccfcf5eacb0cb7", size = 62308, upload-time = "2025-11-15T16:43:48.578Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/39/e7eaf1799466a4aef85b6a4fe7bd175ad2b1c6345066aa33f1f58d4b18d0/asttokens-3.0.1-py3-none-any.whl", hash = "sha256:15a3ebc0f43c2d0a50eeafea25e19046c68398e487b9f1f5b517f7c0f40f976a", size = 27047, upload-time = "2025-11-15T16:43:16.109Z" }, +] + +[[package]] +name = "attrs" +version = "25.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6b/5c/685e6633917e101e5dcb62b9dd76946cbb57c26e133bae9e0cd36033c0a9/attrs-25.4.0.tar.gz", hash = "sha256:16d5969b87f0859ef33a48b35d55ac1be6e42ae49d5e853b597db70c35c57e11", size = 934251, upload-time = "2025-10-06T13:54:44.725Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" }, +] + +[[package]] +name = "billiard" +version = "4.2.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/23/b12ac0bcdfb7360d664f40a00b1bda139cbbbced012c34e375506dbd0143/billiard-4.2.4.tar.gz", hash = "sha256:55f542c371209e03cd5862299b74e52e4fbcba8250ba611ad94276b369b6a85f", size = 156537, upload-time = "2025-11-30T13:28:48.52Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/87/8bab77b323f16d67be364031220069f79159117dd5e43eeb4be2fef1ac9b/billiard-4.2.4-py3-none-any.whl", hash = "sha256:525b42bdec68d2b983347ac312f892db930858495db601b5836ac24e6477cde5", size = 87070, upload-time = "2025-11-30T13:28:47.016Z" }, +] + +[[package]] +name = "brotli" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" }, + { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" }, + { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" }, + { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" }, + { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" }, + { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" }, + { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" }, +] + +[[package]] +name = "caldav" +version = "2.2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "icalendar" }, + { name = "icalendar-searcher" }, + { name = "lxml" }, + { name = "niquests" }, + { name = "recurring-ical-events" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/b9/32c2dedc33d69e01608c42572e86e47511a18a2e2fdb6431e5e5682aba8e/caldav-2.2.3.tar.gz", hash = "sha256:d53e2de4e4aee9e317b23073de6de153077729a40add1a2b2107af5a0db0949c", size = 10072173, upload-time = "2025-12-06T21:18:19.386Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/b3/a16ed3bc5cbcdd269eaea4ae01d1c1a1cab2107dd0f1750043051194a4b0/caldav-2.2.3-py2.py3-none-any.whl", hash = "sha256:0fc5d375a15e469817ffa21276cab372f776d15dc4ba4a3ad34c3e43024f5c67", size = 121169, upload-time = "2025-12-06T21:18:08.288Z" }, +] + +[[package]] +name = "calendars" +version = "0.10.1" +source = { editable = "." } +dependencies = [ + { name = "brotli" }, + { name = "caldav" }, + { name = "celery", extra = ["redis"] }, + { name = "dj-database-url" }, + { name = "django" }, + { name = "django-celery-beat" }, + { name = "django-configurations" }, + { name = "django-cors-headers" }, + { name = "django-countries" }, + { name = "django-filter" }, + { name = "django-lasuite", extra = ["all"] }, + { name = "django-parler" }, + { name = "django-redis" }, + { name = "django-timezone-field" }, + { name = "djangorestframework" }, + { name = "djangorestframework-api-key" }, + { name = "drf-spectacular" }, + { name = "drf-standardized-errors" }, + { name = "factory-boy" }, + { name = "gunicorn" }, + { name = "jsonschema" }, + { name = "mozilla-django-oidc" }, + { name = "nested-multipart-parser" }, + { name = "pillow" }, + { name = "psycopg", extra = ["binary"] }, + { name = "pyjwt" }, + { name = "redis" }, + { name = "requests" }, + { name = "sentry-sdk" }, + { name = "url-normalize" }, + { name = "whitenoise" }, +] + +[package.optional-dependencies] +dev = [ + { name = "django-debug-toolbar" }, + { name = "django-extensions" }, + { name = "drf-spectacular-sidecar" }, + { name = "freezegun" }, + { name = "ipdb" }, + { name = "ipython" }, + { name = "pyfakefs" }, + { name = "pylint" }, + { name = "pylint-django" }, + { name = "pytest" }, + { name = "pytest-cov" }, + { name = "pytest-django" }, + { name = "pytest-icdiff" }, + { name = "pytest-xdist" }, + { name = "responses" }, + { name = "ruff" }, + { name = "types-requests" }, +] + +[package.metadata] +requires-dist = [ + { name = "brotli", specifier = "==1.2.0" }, + { name = "caldav", specifier = "==2.2.3" }, + { name = "celery", extras = ["redis"], specifier = "==5.6.0" }, + { name = "dj-database-url", specifier = "==3.0.1" }, + { name = "django", specifier = "==5.2.9" }, + { name = "django-celery-beat", specifier = "==2.8.1" }, + { name = "django-configurations", specifier = "==2.5.1" }, + { name = "django-cors-headers", specifier = "==4.9.0" }, + { name = "django-countries", specifier = "==8.2.0" }, + { name = "django-debug-toolbar", marker = "extra == 'dev'", specifier = "==6.1.0" }, + { name = "django-extensions", marker = "extra == 'dev'", specifier = "==4.1" }, + { name = "django-filter", specifier = "==25.2" }, + { name = "django-lasuite", extras = ["all"], specifier = "==0.0.21" }, + { name = "django-parler", specifier = "==2.3" }, + { name = "django-redis", specifier = "==6.0.0" }, + { name = "django-timezone-field", specifier = ">=5.1" }, + { name = "djangorestframework", specifier = "==3.16.1" }, + { name = "djangorestframework-api-key", specifier = "==3.1.0" }, + { name = "drf-spectacular", specifier = "==0.29.0" }, + { name = "drf-spectacular-sidecar", marker = "extra == 'dev'", specifier = "==2025.12.1" }, + { name = "drf-standardized-errors", specifier = "==0.15.0" }, + { name = "factory-boy", specifier = "==3.3.3" }, + { name = "freezegun", marker = "extra == 'dev'", specifier = "==1.5.5" }, + { name = "gunicorn", specifier = "==23.0.0" }, + { name = "ipdb", marker = "extra == 'dev'", specifier = "==0.13.13" }, + { name = "ipython", marker = "extra == 'dev'", specifier = "==9.7.0" }, + { name = "jsonschema", specifier = "==4.25.1" }, + { name = "mozilla-django-oidc", specifier = "==4.0.1" }, + { name = "nested-multipart-parser", specifier = "==1.6.0" }, + { name = "pillow", specifier = ">=10.0" }, + { name = "psycopg", extras = ["binary"], specifier = "==3.3.1" }, + { name = "pyfakefs", marker = "extra == 'dev'", specifier = "==5.10.2" }, + { name = "pyjwt", specifier = "==2.10.1" }, + { name = "pylint", marker = "extra == 'dev'", specifier = "<4.0.0" }, + { name = "pylint-django", marker = "extra == 'dev'", specifier = "==2.6.1" }, + { name = "pytest", marker = "extra == 'dev'", specifier = "==9.0.1" }, + { name = "pytest-cov", marker = "extra == 'dev'", specifier = "==7.0.0" }, + { name = "pytest-django", marker = "extra == 'dev'", specifier = "==4.11.1" }, + { name = "pytest-icdiff", marker = "extra == 'dev'", specifier = "==0.9" }, + { name = "pytest-xdist", marker = "extra == 'dev'", specifier = "==3.8.0" }, + { name = "redis", specifier = "<6.0.0" }, + { name = "requests", specifier = "==2.32.5" }, + { name = "responses", marker = "extra == 'dev'", specifier = "==0.25.8" }, + { name = "ruff", marker = "extra == 'dev'", specifier = "==0.14.7" }, + { name = "sentry-sdk", specifier = "==2.46.0" }, + { name = "types-requests", marker = "extra == 'dev'", specifier = "==2.32.4.20250913" }, + { name = "url-normalize", specifier = "==2.2.1" }, + { name = "whitenoise", specifier = "==6.11.0" }, +] +provides-extras = ["dev"] + +[[package]] +name = "celery" +version = "5.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "billiard" }, + { name = "click" }, + { name = "click-didyoumean" }, + { name = "click-plugins" }, + { name = "click-repl" }, + { name = "exceptiongroup" }, + { name = "kombu" }, + { name = "python-dateutil" }, + { name = "tzlocal" }, + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/5f/b681ae3c89290d2ea6562ea96b40f5af6f6fc5f7743e2cd1a19e47721548/celery-5.6.0.tar.gz", hash = "sha256:641405206042d52ae460e4e9751a2e31b06cf80ab836fcf92e0b9311d7ea8113", size = 1712522, upload-time = "2025-11-30T17:39:46.282Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/4e/53a125038d6a814491a0ae3457435c13cf8821eb602292cf9db37ce35f62/celery-5.6.0-py3-none-any.whl", hash = "sha256:33cf01477b175017fc8f22c5ee8a65157591043ba8ca78a443fe703aa910f581", size = 444561, upload-time = "2025-11-30T17:39:44.314Z" }, +] + +[package.optional-dependencies] +redis = [ + { name = "kombu", extra = ["redis"] }, +] + +[[package]] +name = "certifi" +version = "2025.11.12" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/8c/58f469717fa48465e4a50c014a0400602d3c437d7c0c468e17ada824da3a/certifi-2025.11.12.tar.gz", hash = "sha256:d8ab5478f2ecd78af242878415affce761ca6bc54a22a27e026d7c25357c3316", size = 160538, upload-time = "2025-11-12T02:54:51.517Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, +] + +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/13/69/33ddede1939fdd074bce5434295f38fae7136463422fe4fd3e0e89b98062/charset_normalizer-3.4.4.tar.gz", hash = "sha256:94537985111c35f28720e43603b8e7b43a6ecfb2ce1d3058bbe955b73404e21a", size = 129418, upload-time = "2025-10-14T04:42:32.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/97/45/4b3a1239bbacd321068ea6e7ac28875b03ab8bc0aa0966452db17cd36714/charset_normalizer-3.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:e1f185f86a6f3403aa2420e815904c67b2f9ebc443f045edd0de921108345794", size = 208091, upload-time = "2025-10-14T04:41:13.346Z" }, + { url = "https://files.pythonhosted.org/packages/7d/62/73a6d7450829655a35bb88a88fca7d736f9882a27eacdca2c6d505b57e2e/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b39f987ae8ccdf0d2642338faf2abb1862340facc796048b604ef14919e55ed", size = 147936, upload-time = "2025-10-14T04:41:14.461Z" }, + { url = "https://files.pythonhosted.org/packages/89/c5/adb8c8b3d6625bef6d88b251bbb0d95f8205831b987631ab0c8bb5d937c2/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3162d5d8ce1bb98dd51af660f2121c55d0fa541b46dff7bb9b9f86ea1d87de72", size = 144180, upload-time = "2025-10-14T04:41:15.588Z" }, + { url = "https://files.pythonhosted.org/packages/91/ed/9706e4070682d1cc219050b6048bfd293ccf67b3d4f5a4f39207453d4b99/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:81d5eb2a312700f4ecaa977a8235b634ce853200e828fbadf3a9c50bab278328", size = 161346, upload-time = "2025-10-14T04:41:16.738Z" }, + { url = "https://files.pythonhosted.org/packages/d5/0d/031f0d95e4972901a2f6f09ef055751805ff541511dc1252ba3ca1f80cf5/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5bd2293095d766545ec1a8f612559f6b40abc0eb18bb2f5d1171872d34036ede", size = 158874, upload-time = "2025-10-14T04:41:17.923Z" }, + { url = "https://files.pythonhosted.org/packages/f5/83/6ab5883f57c9c801ce5e5677242328aa45592be8a00644310a008d04f922/charset_normalizer-3.4.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8a8b89589086a25749f471e6a900d3f662d1d3b6e2e59dcecf787b1cc3a1894", size = 153076, upload-time = "2025-10-14T04:41:19.106Z" }, + { url = "https://files.pythonhosted.org/packages/75/1e/5ff781ddf5260e387d6419959ee89ef13878229732732ee73cdae01800f2/charset_normalizer-3.4.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc7637e2f80d8530ee4a78e878bce464f70087ce73cf7c1caf142416923b98f1", size = 150601, upload-time = "2025-10-14T04:41:20.245Z" }, + { url = "https://files.pythonhosted.org/packages/d7/57/71be810965493d3510a6ca79b90c19e48696fb1ff964da319334b12677f0/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8bf04158c6b607d747e93949aa60618b61312fe647a6369f88ce2ff16043490", size = 150376, upload-time = "2025-10-14T04:41:21.398Z" }, + { url = "https://files.pythonhosted.org/packages/e5/d5/c3d057a78c181d007014feb7e9f2e65905a6c4ef182c0ddf0de2924edd65/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:554af85e960429cf30784dd47447d5125aaa3b99a6f0683589dbd27e2f45da44", size = 144825, upload-time = "2025-10-14T04:41:22.583Z" }, + { url = "https://files.pythonhosted.org/packages/e6/8c/d0406294828d4976f275ffbe66f00266c4b3136b7506941d87c00cab5272/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:74018750915ee7ad843a774364e13a3db91682f26142baddf775342c3f5b1133", size = 162583, upload-time = "2025-10-14T04:41:23.754Z" }, + { url = "https://files.pythonhosted.org/packages/d7/24/e2aa1f18c8f15c4c0e932d9287b8609dd30ad56dbe41d926bd846e22fb8d/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c0463276121fdee9c49b98908b3a89c39be45d86d1dbaa22957e38f6321d4ce3", size = 150366, upload-time = "2025-10-14T04:41:25.27Z" }, + { url = "https://files.pythonhosted.org/packages/e4/5b/1e6160c7739aad1e2df054300cc618b06bf784a7a164b0f238360721ab86/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:362d61fd13843997c1c446760ef36f240cf81d3ebf74ac62652aebaf7838561e", size = 160300, upload-time = "2025-10-14T04:41:26.725Z" }, + { url = "https://files.pythonhosted.org/packages/7a/10/f882167cd207fbdd743e55534d5d9620e095089d176d55cb22d5322f2afd/charset_normalizer-3.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9a26f18905b8dd5d685d6d07b0cdf98a79f3c7a918906af7cc143ea2e164c8bc", size = 154465, upload-time = "2025-10-14T04:41:28.322Z" }, + { url = "https://files.pythonhosted.org/packages/89/66/c7a9e1b7429be72123441bfdbaf2bc13faab3f90b933f664db506dea5915/charset_normalizer-3.4.4-cp313-cp313-win32.whl", hash = "sha256:9b35f4c90079ff2e2edc5b26c0c77925e5d2d255c42c74fdb70fb49b172726ac", size = 99404, upload-time = "2025-10-14T04:41:29.95Z" }, + { url = "https://files.pythonhosted.org/packages/c4/26/b9924fa27db384bdcd97ab83b4f0a8058d96ad9626ead570674d5e737d90/charset_normalizer-3.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:b435cba5f4f750aa6c0a0d92c541fb79f69a387c91e61f1795227e4ed9cece14", size = 107092, upload-time = "2025-10-14T04:41:31.188Z" }, + { url = "https://files.pythonhosted.org/packages/af/8f/3ed4bfa0c0c72a7ca17f0380cd9e4dd842b09f664e780c13cff1dcf2ef1b/charset_normalizer-3.4.4-cp313-cp313-win_arm64.whl", hash = "sha256:542d2cee80be6f80247095cc36c418f7bddd14f4a6de45af91dfad36d817bba2", size = 100408, upload-time = "2025-10-14T04:41:32.624Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4c/925909008ed5a988ccbb72dcc897407e5d6d3bd72410d69e051fc0c14647/charset_normalizer-3.4.4-py3-none-any.whl", hash = "sha256:7a32c560861a02ff789ad905a2fe94e3f840803362c84fecf1851cb4cf3dc37f", size = 53402, upload-time = "2025-10-14T04:42:31.76Z" }, +] + +[[package]] +name = "click" +version = "8.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/78/01c019cdb5d6498122777c1a43056ebb3ebfeef2076d9d026bfe15583b2b/click-8.3.1-py3-none-any.whl", hash = "sha256:981153a64e25f12d547d3426c367a4857371575ee7ad18df2a6183ab0545b2a6", size = 108274, upload-time = "2025-11-15T20:45:41.139Z" }, +] + +[[package]] +name = "click-didyoumean" +version = "0.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/ce/217289b77c590ea1e7c24242d9ddd6e249e52c795ff10fac2c50062c48cb/click_didyoumean-0.3.1.tar.gz", hash = "sha256:4f82fdff0dbe64ef8ab2279bd6aa3f6a99c3b28c05aa09cbfc07c9d7fbb5a463", size = 3089, upload-time = "2024-03-24T08:22:07.499Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/5b/974430b5ffdb7a4f1941d13d83c64a0395114503cc357c6b9ae4ce5047ed/click_didyoumean-0.3.1-py3-none-any.whl", hash = "sha256:5c4bb6007cfea5f2fd6583a2fb6701a22a41eb98957e63d0fac41c10e7c3117c", size = 3631, upload-time = "2024-03-24T08:22:06.356Z" }, +] + +[[package]] +name = "click-plugins" +version = "1.1.1.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/a4/34847b59150da33690a36da3681d6bbc2ec14ee9a846bc30a6746e5984e4/click_plugins-1.1.1.2.tar.gz", hash = "sha256:d7af3984a99d243c131aa1a828331e7630f4a88a9741fd05c927b204bcf92261", size = 8343, upload-time = "2025-06-25T00:47:37.555Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3d/9a/2abecb28ae875e39c8cad711eb1186d8d14eab564705325e77e4e6ab9ae5/click_plugins-1.1.1.2-py2.py3-none-any.whl", hash = "sha256:008d65743833ffc1f5417bf0e78e8d2c23aab04d9745ba817bd3e71b0feb6aa6", size = 11051, upload-time = "2025-06-25T00:47:36.731Z" }, +] + +[[package]] +name = "click-repl" +version = "0.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "prompt-toolkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/cb/a2/57f4ac79838cfae6912f997b4d1a64a858fb0c86d7fcaae6f7b58d267fca/click-repl-0.3.0.tar.gz", hash = "sha256:17849c23dba3d667247dc4defe1757fff98694e90fe37474f3feebb69ced26a9", size = 10449, upload-time = "2023-06-15T12:43:51.141Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/40/9d857001228658f0d59e97ebd4c346fe73e138c6de1bce61dc568a57c7f8/click_repl-0.3.0-py3-none-any.whl", hash = "sha256:fb7e06deb8da8de86180a33a9da97ac316751c094c6899382da7feeeeb51b812", size = 10289, upload-time = "2023-06-15T12:43:48.626Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "coverage" +version = "7.13.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/23/f9/e92df5e07f3fc8d4c7f9a0f146ef75446bf870351cd37b788cf5897f8079/coverage-7.13.1.tar.gz", hash = "sha256:b7593fe7eb5feaa3fbb461ac79aac9f9fc0387a5ca8080b0c6fe2ca27b091afd", size = 825862, upload-time = "2025-12-28T15:42:56.969Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/a4/e98e689347a1ff1a7f67932ab535cef82eb5e78f32a9e4132e114bbb3a0a/coverage-7.13.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:cb237bfd0ef4d5eb6a19e29f9e528ac67ac3be932ea6b44fb6cc09b9f3ecff78", size = 218951, upload-time = "2025-12-28T15:41:16.653Z" }, + { url = "https://files.pythonhosted.org/packages/32/33/7cbfe2bdc6e2f03d6b240d23dc45fdaf3fd270aaf2d640be77b7f16989ab/coverage-7.13.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1dcb645d7e34dcbcc96cd7c132b1fc55c39263ca62eb961c064eb3928997363b", size = 219325, upload-time = "2025-12-28T15:41:18.609Z" }, + { url = "https://files.pythonhosted.org/packages/59/f6/efdabdb4929487baeb7cb2a9f7dac457d9356f6ad1b255be283d58b16316/coverage-7.13.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3d42df8201e00384736f0df9be2ced39324c3907607d17d50d50116c989d84cd", size = 250309, upload-time = "2025-12-28T15:41:20.629Z" }, + { url = "https://files.pythonhosted.org/packages/12/da/91a52516e9d5aea87d32d1523f9cdcf7a35a3b298e6be05d6509ba3cfab2/coverage-7.13.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fa3edde1aa8807de1d05934982416cb3ec46d1d4d91e280bcce7cca01c507992", size = 252907, upload-time = "2025-12-28T15:41:22.257Z" }, + { url = "https://files.pythonhosted.org/packages/75/38/f1ea837e3dc1231e086db1638947e00d264e7e8c41aa8ecacf6e1e0c05f4/coverage-7.13.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9edd0e01a343766add6817bc448408858ba6b489039eaaa2018474e4001651a4", size = 254148, upload-time = "2025-12-28T15:41:23.87Z" }, + { url = "https://files.pythonhosted.org/packages/7f/43/f4f16b881aaa34954ba446318dea6b9ed5405dd725dd8daac2358eda869a/coverage-7.13.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:985b7836931d033570b94c94713c6dba5f9d3ff26045f72c3e5dbc5fe3361e5a", size = 250515, upload-time = "2025-12-28T15:41:25.437Z" }, + { url = "https://files.pythonhosted.org/packages/84/34/8cba7f00078bd468ea914134e0144263194ce849ec3baad187ffb6203d1c/coverage-7.13.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ffed1e4980889765c84a5d1a566159e363b71d6b6fbaf0bebc9d3c30bc016766", size = 252292, upload-time = "2025-12-28T15:41:28.459Z" }, + { url = "https://files.pythonhosted.org/packages/8c/a4/cffac66c7652d84ee4ac52d3ccb94c015687d3b513f9db04bfcac2ac800d/coverage-7.13.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8842af7f175078456b8b17f1b73a0d16a65dcbdc653ecefeb00a56b3c8c298c4", size = 250242, upload-time = "2025-12-28T15:41:30.02Z" }, + { url = "https://files.pythonhosted.org/packages/f4/78/9a64d462263dde416f3c0067efade7b52b52796f489b1037a95b0dc389c9/coverage-7.13.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:ccd7a6fca48ca9c131d9b0a2972a581e28b13416fc313fb98b6d24a03ce9a398", size = 250068, upload-time = "2025-12-28T15:41:32.007Z" }, + { url = "https://files.pythonhosted.org/packages/69/c8/a8994f5fece06db7c4a97c8fc1973684e178599b42e66280dded0524ef00/coverage-7.13.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0403f647055de2609be776965108447deb8e384fe4a553c119e3ff6bfbab4784", size = 251846, upload-time = "2025-12-28T15:41:33.946Z" }, + { url = "https://files.pythonhosted.org/packages/cc/f7/91fa73c4b80305c86598a2d4e54ba22df6bf7d0d97500944af7ef155d9f7/coverage-7.13.1-cp313-cp313-win32.whl", hash = "sha256:549d195116a1ba1e1ae2f5ca143f9777800f6636eab917d4f02b5310d6d73461", size = 221512, upload-time = "2025-12-28T15:41:35.519Z" }, + { url = "https://files.pythonhosted.org/packages/45/0b/0768b4231d5a044da8f75e097a8714ae1041246bb765d6b5563bab456735/coverage-7.13.1-cp313-cp313-win_amd64.whl", hash = "sha256:5899d28b5276f536fcf840b18b61a9fce23cc3aec1d114c44c07fe94ebeaa500", size = 222321, upload-time = "2025-12-28T15:41:37.371Z" }, + { url = "https://files.pythonhosted.org/packages/9b/b8/bdcb7253b7e85157282450262008f1366aa04663f3e3e4c30436f596c3e2/coverage-7.13.1-cp313-cp313-win_arm64.whl", hash = "sha256:868a2fae76dfb06e87291bcbd4dcbcc778a8500510b618d50496e520bd94d9b9", size = 220949, upload-time = "2025-12-28T15:41:39.553Z" }, + { url = "https://files.pythonhosted.org/packages/70/52/f2be52cc445ff75ea8397948c96c1b4ee14f7f9086ea62fc929c5ae7b717/coverage-7.13.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:67170979de0dacac3f3097d02b0ad188d8edcea44ccc44aaa0550af49150c7dc", size = 219643, upload-time = "2025-12-28T15:41:41.567Z" }, + { url = "https://files.pythonhosted.org/packages/47/79/c85e378eaa239e2edec0c5523f71542c7793fe3340954eafb0bc3904d32d/coverage-7.13.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f80e2bb21bfab56ed7405c2d79d34b5dc0bc96c2c1d2a067b643a09fb756c43a", size = 219997, upload-time = "2025-12-28T15:41:43.418Z" }, + { url = "https://files.pythonhosted.org/packages/fe/9b/b1ade8bfb653c0bbce2d6d6e90cc6c254cbb99b7248531cc76253cb4da6d/coverage-7.13.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f83351e0f7dcdb14d7326c3d8d8c4e915fa685cbfdc6281f9470d97a04e9dfe4", size = 261296, upload-time = "2025-12-28T15:41:45.207Z" }, + { url = "https://files.pythonhosted.org/packages/1f/af/ebf91e3e1a2473d523e87e87fd8581e0aa08741b96265730e2d79ce78d8d/coverage-7.13.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:bb3f6562e89bad0110afbe64e485aac2462efdce6232cdec7862a095dc3412f6", size = 263363, upload-time = "2025-12-28T15:41:47.163Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8b/fb2423526d446596624ac7fde12ea4262e66f86f5120114c3cfd0bb2befa/coverage-7.13.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:77545b5dcda13b70f872c3b5974ac64c21d05e65b1590b441c8560115dc3a0d1", size = 265783, upload-time = "2025-12-28T15:41:49.03Z" }, + { url = "https://files.pythonhosted.org/packages/9b/26/ef2adb1e22674913b89f0fe7490ecadcef4a71fa96f5ced90c60ec358789/coverage-7.13.1-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a4d240d260a1aed814790bbe1f10a5ff31ce6c21bc78f0da4a1e8268d6c80dbd", size = 260508, upload-time = "2025-12-28T15:41:51.035Z" }, + { url = "https://files.pythonhosted.org/packages/ce/7d/f0f59b3404caf662e7b5346247883887687c074ce67ba453ea08c612b1d5/coverage-7.13.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d2287ac9360dec3837bfdad969963a5d073a09a85d898bd86bea82aa8876ef3c", size = 263357, upload-time = "2025-12-28T15:41:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b1/29896492b0b1a047604d35d6fa804f12818fa30cdad660763a5f3159e158/coverage-7.13.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0d2c11f3ea4db66b5cbded23b20185c35066892c67d80ec4be4bab257b9ad1e0", size = 260978, upload-time = "2025-12-28T15:41:54.589Z" }, + { url = "https://files.pythonhosted.org/packages/48/f2/971de1238a62e6f0a4128d37adadc8bb882ee96afbe03ff1570291754629/coverage-7.13.1-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:3fc6a169517ca0d7ca6846c3c5392ef2b9e38896f61d615cb75b9e7134d4ee1e", size = 259877, upload-time = "2025-12-28T15:41:56.263Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fc/0474efcbb590ff8628830e9aaec5f1831594874360e3251f1fdec31d07a3/coverage-7.13.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d10a2ed46386e850bb3de503a54f9fe8192e5917fcbb143bfef653a9355e9a53", size = 262069, upload-time = "2025-12-28T15:41:58.093Z" }, + { url = "https://files.pythonhosted.org/packages/88/4f/3c159b7953db37a7b44c0eab8a95c37d1aa4257c47b4602c04022d5cb975/coverage-7.13.1-cp313-cp313t-win32.whl", hash = "sha256:75a6f4aa904301dab8022397a22c0039edc1f51e90b83dbd4464b8a38dc87842", size = 222184, upload-time = "2025-12-28T15:41:59.763Z" }, + { url = "https://files.pythonhosted.org/packages/58/a5/6b57d28f81417f9335774f20679d9d13b9a8fb90cd6160957aa3b54a2379/coverage-7.13.1-cp313-cp313t-win_amd64.whl", hash = "sha256:309ef5706e95e62578cda256b97f5e097916a2c26247c287bbe74794e7150df2", size = 223250, upload-time = "2025-12-28T15:42:01.52Z" }, + { url = "https://files.pythonhosted.org/packages/81/7c/160796f3b035acfbb58be80e02e484548595aa67e16a6345e7910ace0a38/coverage-7.13.1-cp313-cp313t-win_arm64.whl", hash = "sha256:92f980729e79b5d16d221038dbf2e8f9a9136afa072f9d5d6ed4cb984b126a09", size = 221521, upload-time = "2025-12-28T15:42:03.275Z" }, + { url = "https://files.pythonhosted.org/packages/cc/48/d9f421cb8da5afaa1a64570d9989e00fb7955e6acddc5a12979f7666ef60/coverage-7.13.1-py3-none-any.whl", hash = "sha256:2016745cb3ba554469d02819d78958b571792bb68e31302610e898f80dd3a573", size = 210722, upload-time = "2025-12-28T15:42:54.901Z" }, +] + +[[package]] +name = "cron-descriptor" +version = "2.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/31/0b21d1599656b2ffa6043e51ca01041cd1c0f6dacf5a3e2b620ed120e7d8/cron_descriptor-2.0.6.tar.gz", hash = "sha256:e39d2848e1d8913cfb6e3452e701b5eec662ee18bea8cc5aa53ee1a7bb217157", size = 49456, upload-time = "2025-09-03T16:30:22.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/21/cc/361326a54ad92e2e12845ad15e335a4e14b8953665007fb514d3393dfb0f/cron_descriptor-2.0.6-py3-none-any.whl", hash = "sha256:3a1c0d837c0e5a32e415f821b36cf758eb92d510e6beff8fbfe4fa16573d93d6", size = 74446, upload-time = "2025-09-03T16:30:21.397Z" }, +] + +[[package]] +name = "cryptography" +version = "46.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9f/33/c00162f49c0e2fe8064a62cb92b93e50c74a72bc370ab92f86112b33ff62/cryptography-46.0.3.tar.gz", hash = "sha256:a8b17438104fed022ce745b362294d9ce35b4c2e45c1d958ad4a4b019285f4a1", size = 749258, upload-time = "2025-10-15T23:18:31.74Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/42/9c391dd801d6cf0d561b5890549d4b27bafcc53b39c31a817e69d87c625b/cryptography-46.0.3-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:109d4ddfadf17e8e7779c39f9b18111a09efb969a301a31e987416a0191ed93a", size = 7225004, upload-time = "2025-10-15T23:16:52.239Z" }, + { url = "https://files.pythonhosted.org/packages/1c/67/38769ca6b65f07461eb200e85fc1639b438bdc667be02cf7f2cd6a64601c/cryptography-46.0.3-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:09859af8466b69bc3c27bdf4f5d84a665e0f7ab5088412e9e2ec49758eca5cbc", size = 4296667, upload-time = "2025-10-15T23:16:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/5c/49/498c86566a1d80e978b42f0d702795f69887005548c041636df6ae1ca64c/cryptography-46.0.3-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:01ca9ff2885f3acc98c29f1860552e37f6d7c7d013d7334ff2a9de43a449315d", size = 4450807, upload-time = "2025-10-15T23:16:56.414Z" }, + { url = "https://files.pythonhosted.org/packages/4b/0a/863a3604112174c8624a2ac3c038662d9e59970c7f926acdcfaed8d61142/cryptography-46.0.3-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6eae65d4c3d33da080cff9c4ab1f711b15c1d9760809dad6ea763f3812d254cb", size = 4299615, upload-time = "2025-10-15T23:16:58.442Z" }, + { url = "https://files.pythonhosted.org/packages/64/02/b73a533f6b64a69f3cd3872acb6ebc12aef924d8d103133bb3ea750dc703/cryptography-46.0.3-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5bf0ed4490068a2e72ac03d786693adeb909981cc596425d09032d372bcc849", size = 4016800, upload-time = "2025-10-15T23:17:00.378Z" }, + { url = "https://files.pythonhosted.org/packages/25/d5/16e41afbfa450cde85a3b7ec599bebefaef16b5c6ba4ec49a3532336ed72/cryptography-46.0.3-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:5ecfccd2329e37e9b7112a888e76d9feca2347f12f37918facbb893d7bb88ee8", size = 4984707, upload-time = "2025-10-15T23:17:01.98Z" }, + { url = "https://files.pythonhosted.org/packages/c9/56/e7e69b427c3878352c2fb9b450bd0e19ed552753491d39d7d0a2f5226d41/cryptography-46.0.3-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a2c0cd47381a3229c403062f764160d57d4d175e022c1df84e168c6251a22eec", size = 4482541, upload-time = "2025-10-15T23:17:04.078Z" }, + { url = "https://files.pythonhosted.org/packages/78/f6/50736d40d97e8483172f1bb6e698895b92a223dba513b0ca6f06b2365339/cryptography-46.0.3-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:549e234ff32571b1f4076ac269fcce7a808d3bf98b76c8dd560e42dbc66d7d91", size = 4299464, upload-time = "2025-10-15T23:17:05.483Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/d8e26b1a855f19d9994a19c702fa2e93b0456beccbcfe437eda00e0701f2/cryptography-46.0.3-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:c0a7bb1a68a5d3471880e264621346c48665b3bf1c3759d682fc0864c540bd9e", size = 4950838, upload-time = "2025-10-15T23:17:07.425Z" }, + { url = "https://files.pythonhosted.org/packages/8f/29/798fc4ec461a1c9e9f735f2fc58741b0daae30688f41b2497dcbc9ed1355/cryptography-46.0.3-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:10b01676fc208c3e6feeb25a8b83d81767e8059e1fe86e1dc62d10a3018fa926", size = 4481596, upload-time = "2025-10-15T23:17:09.343Z" }, + { url = "https://files.pythonhosted.org/packages/15/8d/03cd48b20a573adfff7652b76271078e3045b9f49387920e7f1f631d125e/cryptography-46.0.3-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:0abf1ffd6e57c67e92af68330d05760b7b7efb243aab8377e583284dbab72c71", size = 4426782, upload-time = "2025-10-15T23:17:11.22Z" }, + { url = "https://files.pythonhosted.org/packages/fa/b1/ebacbfe53317d55cf33165bda24c86523497a6881f339f9aae5c2e13e57b/cryptography-46.0.3-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a04bee9ab6a4da801eb9b51f1b708a1b5b5c9eb48c03f74198464c66f0d344ac", size = 4698381, upload-time = "2025-10-15T23:17:12.829Z" }, + { url = "https://files.pythonhosted.org/packages/96/92/8a6a9525893325fc057a01f654d7efc2c64b9de90413adcf605a85744ff4/cryptography-46.0.3-cp311-abi3-win32.whl", hash = "sha256:f260d0d41e9b4da1ed1e0f1ce571f97fe370b152ab18778e9e8f67d6af432018", size = 3055988, upload-time = "2025-10-15T23:17:14.65Z" }, + { url = "https://files.pythonhosted.org/packages/7e/bf/80fbf45253ea585a1e492a6a17efcb93467701fa79e71550a430c5e60df0/cryptography-46.0.3-cp311-abi3-win_amd64.whl", hash = "sha256:a9a3008438615669153eb86b26b61e09993921ebdd75385ddd748702c5adfddb", size = 3514451, upload-time = "2025-10-15T23:17:16.142Z" }, + { url = "https://files.pythonhosted.org/packages/2e/af/9b302da4c87b0beb9db4e756386a7c6c5b8003cd0e742277888d352ae91d/cryptography-46.0.3-cp311-abi3-win_arm64.whl", hash = "sha256:5d7f93296ee28f68447397bf5198428c9aeeab45705a55d53a6343455dcb2c3c", size = 2928007, upload-time = "2025-10-15T23:17:18.04Z" }, + { url = "https://files.pythonhosted.org/packages/fd/23/45fe7f376a7df8daf6da3556603b36f53475a99ce4faacb6ba2cf3d82021/cryptography-46.0.3-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:cb3d760a6117f621261d662bccc8ef5bc32ca673e037c83fbe565324f5c46936", size = 7218248, upload-time = "2025-10-15T23:17:46.294Z" }, + { url = "https://files.pythonhosted.org/packages/27/32/b68d27471372737054cbd34c84981f9edbc24fe67ca225d389799614e27f/cryptography-46.0.3-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:4b7387121ac7d15e550f5cb4a43aef2559ed759c35df7336c402bb8275ac9683", size = 4294089, upload-time = "2025-10-15T23:17:48.269Z" }, + { url = "https://files.pythonhosted.org/packages/26/42/fa8389d4478368743e24e61eea78846a0006caffaf72ea24a15159215a14/cryptography-46.0.3-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:15ab9b093e8f09daab0f2159bb7e47532596075139dd74365da52ecc9cb46c5d", size = 4440029, upload-time = "2025-10-15T23:17:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/5f/eb/f483db0ec5ac040824f269e93dd2bd8a21ecd1027e77ad7bdf6914f2fd80/cryptography-46.0.3-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:46acf53b40ea38f9c6c229599a4a13f0d46a6c3fa9ef19fc1a124d62e338dfa0", size = 4297222, upload-time = "2025-10-15T23:17:51.357Z" }, + { url = "https://files.pythonhosted.org/packages/fd/cf/da9502c4e1912cb1da3807ea3618a6829bee8207456fbbeebc361ec38ba3/cryptography-46.0.3-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:10ca84c4668d066a9878890047f03546f3ae0a6b8b39b697457b7757aaf18dbc", size = 4012280, upload-time = "2025-10-15T23:17:52.964Z" }, + { url = "https://files.pythonhosted.org/packages/6b/8f/9adb86b93330e0df8b3dcf03eae67c33ba89958fc2e03862ef1ac2b42465/cryptography-46.0.3-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:36e627112085bb3b81b19fed209c05ce2a52ee8b15d161b7c643a7d5a88491f3", size = 4978958, upload-time = "2025-10-15T23:17:54.965Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a0/5fa77988289c34bdb9f913f5606ecc9ada1adb5ae870bd0d1054a7021cc4/cryptography-46.0.3-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1000713389b75c449a6e979ffc7dcc8ac90b437048766cef052d4d30b8220971", size = 4473714, upload-time = "2025-10-15T23:17:56.754Z" }, + { url = "https://files.pythonhosted.org/packages/14/e5/fc82d72a58d41c393697aa18c9abe5ae1214ff6f2a5c18ac470f92777895/cryptography-46.0.3-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:b02cf04496f6576afffef5ddd04a0cb7d49cf6be16a9059d793a30b035f6b6ac", size = 4296970, upload-time = "2025-10-15T23:17:58.588Z" }, + { url = "https://files.pythonhosted.org/packages/78/06/5663ed35438d0b09056973994f1aec467492b33bd31da36e468b01ec1097/cryptography-46.0.3-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:71e842ec9bc7abf543b47cf86b9a743baa95f4677d22baa4c7d5c69e49e9bc04", size = 4940236, upload-time = "2025-10-15T23:18:00.897Z" }, + { url = "https://files.pythonhosted.org/packages/fc/59/873633f3f2dcd8a053b8dd1d38f783043b5fce589c0f6988bf55ef57e43e/cryptography-46.0.3-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:402b58fc32614f00980b66d6e56a5b4118e6cb362ae8f3fda141ba4689bd4506", size = 4472642, upload-time = "2025-10-15T23:18:02.749Z" }, + { url = "https://files.pythonhosted.org/packages/3d/39/8e71f3930e40f6877737d6f69248cf74d4e34b886a3967d32f919cc50d3b/cryptography-46.0.3-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ef639cb3372f69ec44915fafcd6698b6cc78fbe0c2ea41be867f6ed612811963", size = 4423126, upload-time = "2025-10-15T23:18:04.85Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c7/f65027c2810e14c3e7268353b1681932b87e5a48e65505d8cc17c99e36ae/cryptography-46.0.3-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3b51b8ca4f1c6453d8829e1eb7299499ca7f313900dd4d89a24b8b87c0a780d4", size = 4686573, upload-time = "2025-10-15T23:18:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/0a/6e/1c8331ddf91ca4730ab3086a0f1be19c65510a33b5a441cb334e7a2d2560/cryptography-46.0.3-cp38-abi3-win32.whl", hash = "sha256:6276eb85ef938dc035d59b87c8a7dc559a232f954962520137529d77b18ff1df", size = 3036695, upload-time = "2025-10-15T23:18:08.672Z" }, + { url = "https://files.pythonhosted.org/packages/90/45/b0d691df20633eff80955a0fc7695ff9051ffce8b69741444bd9ed7bd0db/cryptography-46.0.3-cp38-abi3-win_amd64.whl", hash = "sha256:416260257577718c05135c55958b674000baef9a1c7d9e8f306ec60d71db850f", size = 3501720, upload-time = "2025-10-15T23:18:10.632Z" }, + { url = "https://files.pythonhosted.org/packages/e8/cb/2da4cc83f5edb9c3257d09e1e7ab7b23f049c7962cae8d842bbef0a9cec9/cryptography-46.0.3-cp38-abi3-win_arm64.whl", hash = "sha256:d89c3468de4cdc4f08a57e214384d0471911a3830fcdaf7a8cc587e42a866372", size = 2918740, upload-time = "2025-10-15T23:18:12.277Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "dill" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/12/80/630b4b88364e9a8c8c5797f4602d0f76ef820909ee32f0bacb9f90654042/dill-0.4.0.tar.gz", hash = "sha256:0633f1d2df477324f53a895b02c901fb961bdbf65a17122586ea7019292cbcf0", size = 186976, upload-time = "2025-04-16T00:41:48.867Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/50/3d/9373ad9c56321fdab5b41197068e1d8c25883b3fea29dd361f9b55116869/dill-0.4.0-py3-none-any.whl", hash = "sha256:44f54bf6412c2c8464c14e8243eb163690a9800dbe2c367330883b19c7561049", size = 119668, upload-time = "2025-04-16T00:41:47.671Z" }, +] + +[[package]] +name = "dj-database-url" +version = "3.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/75/05/2ec51009f4ce424877dbd8ad95868faec0c3494ed0ff1635f9ab53d9e0ee/dj_database_url-3.0.1.tar.gz", hash = "sha256:8994961efb888fc6bf8c41550870c91f6f7691ca751888ebaa71442b7f84eff8", size = 12556, upload-time = "2025-07-02T09:40:11.424Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/aa/5e/86a43c6fdaa41c12d58e4ff3ebbfd6b71a7cb0360a08614e3754ef2e9afb/dj_database_url-3.0.1-py3-none-any.whl", hash = "sha256:43950018e1eeea486bf11136384aec0fe55b29fe6fd8a44553231b85661d9383", size = 8808, upload-time = "2025-07-02T09:40:26.326Z" }, +] + +[[package]] +name = "django" +version = "5.2.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "sqlparse" }, + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/1c/188ce85ee380f714b704283013434976df8d3a2df8e735221a02605b6794/django-5.2.9.tar.gz", hash = "sha256:16b5ccfc5e8c27e6c0561af551d2ea32852d7352c67d452ae3e76b4f6b2ca495", size = 10848762, upload-time = "2025-12-02T14:01:08.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/b0/7f42bfc38b8f19b78546d47147e083ed06e12fc29c42da95655e0962c6c2/django-5.2.9-py3-none-any.whl", hash = "sha256:3a4ea88a70370557ab1930b332fd2887a9f48654261cdffda663fef5976bb00a", size = 8290652, upload-time = "2025-12-02T14:01:03.485Z" }, +] + +[[package]] +name = "django-celery-beat" +version = "2.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "celery" }, + { name = "cron-descriptor" }, + { name = "django" }, + { name = "django-timezone-field" }, + { name = "python-crontab" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/aa/11/0c8b412869b4fda72828572068312b10aafe7ccef7b41af3633af31f9d4b/django_celery_beat-2.8.1.tar.gz", hash = "sha256:dfad0201c0ac50c91a34700ef8fa0a10ee098cc7f3375fe5debed79f2204f80a", size = 175802, upload-time = "2025-05-13T06:58:29.246Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/e5/3a0167044773dee989b498e9a851fc1663bea9ab879f1179f7b8a827ac10/django_celery_beat-2.8.1-py3-none-any.whl", hash = "sha256:da2b1c6939495c05a551717509d6e3b79444e114a027f7b77bf3727c2a39d171", size = 104833, upload-time = "2025-05-13T06:58:27.309Z" }, +] + +[[package]] +name = "django-configurations" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/67/5fec7c64118209b20bde6b6f8a82300d9f4a56f7303293e2b31f9940e721/django-configurations-2.5.1.tar.gz", hash = "sha256:6e5083757e2bbdf9bb7850567536b96a93515f6b17503d74928ff628db2e0e94", size = 43225, upload-time = "2024-03-27T11:40:53.134Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/4e/1cc7fd6c0292d56e104f0c8c54ed71c35cafa06838d8f910b918589bf596/django_configurations-2.5.1-py3-none-any.whl", hash = "sha256:ceb84858da2dac846b15e715c2fd936cfc4c7917c074aff8d31700564093955e", size = 17357, upload-time = "2024-03-27T11:42:02.951Z" }, +] + +[[package]] +name = "django-cors-headers" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/21/39/55822b15b7ec87410f34cd16ce04065ff390e50f9e29f31d6d116fc80456/django_cors_headers-4.9.0.tar.gz", hash = "sha256:fe5d7cb59fdc2c8c646ce84b727ac2bca8912a247e6e68e1fb507372178e59e8", size = 21458, upload-time = "2025-09-18T10:40:52.326Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/d8/19ed1e47badf477d17fb177c1c19b5a21da0fd2d9f093f23be3fb86c5fab/django_cors_headers-4.9.0-py3-none-any.whl", hash = "sha256:15c7f20727f90044dcee2216a9fd7303741a864865f0c3657e28b7056f61b449", size = 12809, upload-time = "2025-09-18T10:40:50.843Z" }, +] + +[[package]] +name = "django-countries" +version = "8.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asgiref" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/67/2e/ed67f8f460d1de25ee64fca5d7f219680f944fc8ac5a29fbede3574dc3db/django_countries-8.2.0.tar.gz", hash = "sha256:6df3883180599052c7dfa9a8be0601792441cfb248935dc229ad1ac92e9e39e3", size = 2455542, upload-time = "2025-11-24T19:57:08.071Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/3c/9ebd7ed021b7c519bac954bc88146bc870e7d3c8db2580fa67268464fd2e/django_countries-8.2.0-py3-none-any.whl", hash = "sha256:2b2617bec7c15dc735bdec38ae89f0058e38fddfffdb19a7f6b75ef1e3d5380f", size = 3776079, upload-time = "2025-11-24T19:57:05.576Z" }, +] + +[[package]] +name = "django-debug-toolbar" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "sqlparse" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/50/acae2dd379164f6f4c6b6b36fd48a4d21b02095a03f4df7c30a8d1f1a62c/django_debug_toolbar-6.1.0.tar.gz", hash = "sha256:e962ec350c9be8bdba918138e975a9cdb193f60ec396af2bb71b769e8e165519", size = 309141, upload-time = "2025-10-30T19:50:39.458Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/72/685c978af45ad08257e2c69687a873eda6b6531c79b6e6091794c41c5ff6/django_debug_toolbar-6.1.0-py3-none-any.whl", hash = "sha256:e214dea4494087e7cebdcea84223819c5eb97f9de3110a3665ad673f0ba98413", size = 269069, upload-time = "2025-10-30T19:50:37.71Z" }, +] + +[[package]] +name = "django-extensions" +version = "4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6d/b3/ed0f54ed706ec0b54fd251cc0364a249c6cd6c6ec97f04dc34be5e929eac/django_extensions-4.1.tar.gz", hash = "sha256:7b70a4d28e9b840f44694e3f7feb54f55d495f8b3fa6c5c0e5e12bcb2aa3cdeb", size = 283078, upload-time = "2025-04-11T01:15:39.617Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/96/d967ca440d6a8e3861120f51985d8e5aec79b9a8bdda16041206adfe7adc/django_extensions-4.1-py3-none-any.whl", hash = "sha256:0699a7af28f2523bf8db309a80278519362cd4b6e1fd0a8cd4bf063e1e023336", size = 232980, upload-time = "2025-04-11T01:15:37.701Z" }, +] + +[[package]] +name = "django-filter" +version = "25.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2c/e4/465d2699cd388c0005fb8d6ae6709f239917c6d8790ac35719676fffdcf3/django_filter-25.2.tar.gz", hash = "sha256:760e984a931f4468d096f5541787efb8998c61217b73006163bf2f9523fe8f23", size = 143818, upload-time = "2025-10-05T09:51:31.521Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/40/6a02495c5658beb1f31eb09952d8aa12ef3c2a66342331ce3a35f7132439/django_filter-25.2-py3-none-any.whl", hash = "sha256:9c0f8609057309bba611062fe1b720b4a873652541192d232dd28970383633e3", size = 94145, upload-time = "2025-10-05T09:51:29.728Z" }, +] + +[[package]] +name = "django-lasuite" +version = "0.0.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "joserfc" }, + { name = "mozilla-django-oidc" }, + { name = "requests" }, + { name = "requests-toolbelt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/3b/b75a5767616d8f1781a9710b5bc3edd77c92b58bd6773dc9c972d45ea307/django_lasuite-0.0.21.tar.gz", hash = "sha256:99af5b38dd78eb0b80500a27eb352494682ea68ae5836795ae36a7962bca4dd1", size = 31772, upload-time = "2025-12-04T15:12:01.938Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4c/fd/07f555c576b2d61f7e1444261055b2c7dcc208676b5e2cb53405946fef53/django_lasuite-0.0.21-py3-none-any.whl", hash = "sha256:039db5784bae1e6cb34f718fa12d749a263d8642de68f9fb72ea62226257b144", size = 47572, upload-time = "2025-12-04T15:12:00.443Z" }, +] + +[package.optional-dependencies] +all = [ + { name = "celery" }, + { name = "django-configurations" }, +] + +[[package]] +name = "django-parler" +version = "2.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8c/2b/2423d31620efe8ab0d0390e60afab4f9cc2e62d4bf39fe0e05df0eef1b93/django-parler-2.3.tar.gz", hash = "sha256:2c8f5012ceb5e49af93b16ea3fe4d0c83d70b91b2d0f470c05d7d742b6f3083d", size = 69167, upload-time = "2021-11-18T09:32:28.959Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/38/11f1a7e3d56f3a6b74cf99e307f2554b741cadebc9b1c45b05e2ec1f35a2/django_parler-2.3-py3-none-any.whl", hash = "sha256:8f6c8061e4b5690f1ee2d8e5760940ef06bf78a5bfa033d11178377559c749cf", size = 83288, upload-time = "2021-11-18T09:32:27.193Z" }, +] + +[[package]] +name = "django-redis" +version = "6.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "redis" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/53/dbcfa1e528e0d6c39947092625b2c89274b5d88f14d357cee53c4d6dbbd4/django_redis-6.0.0.tar.gz", hash = "sha256:2d9cb12a20424a4c4dde082c6122f486628bae2d9c2bee4c0126a4de7fda00dd", size = 56904, upload-time = "2025-06-17T18:15:46.376Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/79/055dfcc508cfe9f439d9f453741188d633efa9eab90fc78a67b0ab50b137/django_redis-6.0.0-py3-none-any.whl", hash = "sha256:20bf0063a8abee567eb5f77f375143c32810c8700c0674ced34737f8de4e36c0", size = 33687, upload-time = "2025-06-17T18:15:34.165Z" }, +] + +[[package]] +name = "django-timezone-field" +version = "7.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/05/9b93a66452cdb8a08ab26f08d5766d2332673e659a8b2aeb73f2a904d421/django_timezone_field-7.2.1.tar.gz", hash = "sha256:def846f9e7200b7b8f2a28fcce2b78fb2d470f6a9f272b07c4e014f6ba4c6d2e", size = 13096, upload-time = "2025-12-06T23:50:44.591Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/7f/d885667401515b467f84569c56075bc9add72c9fd425fca51a25f4c997e1/django_timezone_field-7.2.1-py3-none-any.whl", hash = "sha256:276915b72c5816f57c3baf9e43f816c695ef940d1b21f91ebf6203c09bf4ad44", size = 13284, upload-time = "2025-12-06T23:50:43.302Z" }, +] + +[[package]] +name = "djangorestframework" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8a/95/5376fe618646fde6899b3cdc85fd959716bb67542e273a76a80d9f326f27/djangorestframework-3.16.1.tar.gz", hash = "sha256:166809528b1aced0a17dc66c24492af18049f2c9420dbd0be29422029cfc3ff7", size = 1089735, upload-time = "2025-08-06T17:50:53.251Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/ce/bf8b9d3f415be4ac5588545b5fcdbbb841977db1c1d923f7568eeabe1689/djangorestframework-3.16.1-py3-none-any.whl", hash = "sha256:33a59f47fb9c85ede792cbf88bde71893bcda0667bc573f784649521f1102cec", size = 1080442, upload-time = "2025-08-06T17:50:50.667Z" }, +] + +[[package]] +name = "djangorestframework-api-key" +version = "3.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/d9/d187626f67eec3d8c7fb170009ffc323e70553dbac8832ca051f4c7e0a53/djangorestframework_api_key-3.1.0.tar.gz", hash = "sha256:7e9c88360933b3c46467d80645a50cf36697674c7856a737a1c674d570860ac9", size = 36922, upload-time = "2025-04-04T08:53:19.422Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/50/29fd576a9162ff3fcd0423ae5a30e7f9610a438329dd20081a60c758f100/djangorestframework_api_key-3.1.0-py3-none-any.whl", hash = "sha256:1b6ed7d89308cf872b29084cf68f9b7171f7efd2b8f84f480c09aa4232f910c1", size = 15664, upload-time = "2025-04-04T08:53:18.228Z" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "drf-spectacular" +version = "0.29.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, + { name = "inflection" }, + { name = "jsonschema" }, + { name = "pyyaml" }, + { name = "uritemplate" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/0e/a4f50d83e76cbe797eda88fc0083c8ca970cfa362b5586359ef06ec6f70a/drf_spectacular-0.29.0.tar.gz", hash = "sha256:0a069339ea390ce7f14a75e8b5af4a0860a46e833fd4af027411a3e94fc1a0cc", size = 241722, upload-time = "2025-11-02T03:40:26.348Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d9/502c56fc3ca960075d00956283f1c44e8cafe433dada03f9ed2821f3073b/drf_spectacular-0.29.0-py3-none-any.whl", hash = "sha256:d1ee7c9535d89848affb4427347f7c4a22c5d22530b8842ef133d7b72e19b41a", size = 105433, upload-time = "2025-11-02T03:40:24.823Z" }, +] + +[[package]] +name = "drf-spectacular-sidecar" +version = "2025.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/9a/5f1a83bd7bb1937a6347e148fbd116195abb16f7179f7c1b34b3ad2befd8/drf_spectacular_sidecar-2025.12.1.tar.gz", hash = "sha256:d25d82ea2e6176ce4583812f73ac9f177dcd56141c11a9e9bf35f1b1878d5044", size = 2460914, upload-time = "2025-12-01T11:26:59.798Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/03/0c6d70dcf24c4af0648bd0e8543fb9ad6c1952d9dcf01df729e4f4458d4c/drf_spectacular_sidecar-2025.12.1-py3-none-any.whl", hash = "sha256:dd28870327b92a0e3c9b6809147fd3e74ec449176daeae291af34eda176236c1", size = 2482183, upload-time = "2025-12-01T11:26:58.176Z" }, +] + +[[package]] +name = "drf-standardized-errors" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "django" }, + { name = "djangorestframework" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ea/5d/9301be05081261cebdc000f9fbad51dc2b2732f9decd8da693f7c2daae29/drf_standardized_errors-0.15.0.tar.gz", hash = "sha256:83112d072e751eb444c2f16ab4618273b912cffc07f12b81998060fdfa2eb655", size = 60729, upload-time = "2025-06-09T07:47:56.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/94/4e7721ff51cb10aa826cb27f3bf015e8d94d7f898c19c2b650d822019e5b/drf_standardized_errors-0.15.0-py3-none-any.whl", hash = "sha256:75dcfec11433a16c81f8c5948a5cd2932cd5b02f426f64ca82020a78c155b263", size = 25673, upload-time = "2025-06-09T07:47:55.042Z" }, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8a/0e/97c33bf5009bdbac74fd2beace167cab3f978feb69cc36f1ef79360d6c4e/exceptiongroup-1.3.1-py3-none-any.whl", hash = "sha256:a7a39a3bd276781e98394987d3a5701d0c4edffb633bb7a5144577f82c773598", size = 16740, upload-time = "2025-11-21T23:01:53.443Z" }, +] + +[[package]] +name = "execnet" +version = "2.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/89/780e11f9588d9e7128a3f87788354c7946a9cbb1401ad38a48c4db9a4f07/execnet-2.1.2.tar.gz", hash = "sha256:63d83bfdd9a23e35b9c6a3261412324f964c2ec8dcd8d3c6916ee9373e0befcd", size = 166622, upload-time = "2025-11-12T09:56:37.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ab/84/02fc1827e8cdded4aa65baef11296a9bbe595c474f0d6d758af082d849fd/execnet-2.1.2-py3-none-any.whl", hash = "sha256:67fba928dd5a544b783f6056f449e5e3931a5c378b128bc18501f7ea79e296ec", size = 40708, upload-time = "2025-11-12T09:56:36.333Z" }, +] + +[[package]] +name = "executing" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/28/c14e053b6762b1044f34a13aab6859bbf40456d37d23aa286ac24cfd9a5d/executing-2.2.1.tar.gz", hash = "sha256:3632cc370565f6648cc328b32435bd120a1e4ebb20c77e3fdde9a13cd1e533c4", size = 1129488, upload-time = "2025-09-01T09:48:10.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, +] + +[[package]] +name = "factory-boy" +version = "3.3.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "faker" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ba/98/75cacae9945f67cfe323829fc2ac451f64517a8a330b572a06a323997065/factory_boy-3.3.3.tar.gz", hash = "sha256:866862d226128dfac7f2b4160287e899daf54f2612778327dd03d0e2cb1e3d03", size = 164146, upload-time = "2025-02-03T09:49:04.433Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/8d/2bc5f5546ff2ccb3f7de06742853483ab75bf74f36a92254702f8baecc79/factory_boy-3.3.3-py2.py3-none-any.whl", hash = "sha256:1c39e3289f7e667c4285433f305f8d506efc2fe9c73aaea4151ebd5cdea394fc", size = 37036, upload-time = "2025-02-03T09:49:01.659Z" }, +] + +[[package]] +name = "faker" +version = "39.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/b9/0897fb5888ddda099dc0f314a8a9afb5faa7e52eaf6865c00686dfb394db/faker-39.0.0.tar.gz", hash = "sha256:ddae46d3b27e01cea7894651d687b33bcbe19a45ef044042c721ceac6d3da0ff", size = 1941757, upload-time = "2025-12-17T19:19:04.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/5a/26cdb1b10a55ac6eb11a738cea14865fa753606c4897d7be0f5dc230df00/faker-39.0.0-py3-none-any.whl", hash = "sha256:c72f1fca8f1a24b8da10fcaa45739135a19772218ddd61b86b7ea1b8c790dce7", size = 1980775, upload-time = "2025-12-17T19:19:02.926Z" }, +] + +[[package]] +name = "freezegun" +version = "1.5.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/95/dd/23e2f4e357f8fd3bdff613c1fe4466d21bfb00a6177f238079b17f7b1c84/freezegun-1.5.5.tar.gz", hash = "sha256:ac7742a6cc6c25a2c35e9292dfd554b897b517d2dec26891a2e8debf205cb94a", size = 35914, upload-time = "2025-08-09T10:39:08.338Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/2e/b41d8a1a917d6581fc27a35d05561037b048e47df50f27f8ac9c7e27a710/freezegun-1.5.5-py3-none-any.whl", hash = "sha256:cd557f4a75cf074e84bc374249b9dd491eaeacd61376b9eb3c423282211619d2", size = 19266, upload-time = "2025-08-09T10:39:06.636Z" }, +] + +[[package]] +name = "gunicorn" +version = "23.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "icalendar" +version = "6.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "python-dateutil" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5d/70/458092b3e7c15783423fe64d07e63ea3311a597e723be6a1060513e3db93/icalendar-6.3.2.tar.gz", hash = "sha256:e0c10ecbfcebe958d33af7d491f6e6b7580d11d475f2eeb29532d0424f9110a1", size = 178422, upload-time = "2025-11-05T12:49:32.286Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/06/ee/2ff96bb5bd88fe03ab90aedf5180f96dc0f3ae4648ca264b473055bcaaff/icalendar-6.3.2-py3-none-any.whl", hash = "sha256:d400e9c9bb8c025e5a3c77c236941bb690494be52528a0b43cc7e8b7c9505064", size = 242403, upload-time = "2025-11-05T12:49:30.691Z" }, +] + +[[package]] +name = "icalendar-searcher" +version = "1.0.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "icalendar" }, + { name = "recurring-ical-events" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/e7/00c6ac3f10689515efb2cf1ab620f18c51c4c110796d6075a6d3ba5b82e2/icalendar_searcher-1.0.3.tar.gz", hash = "sha256:fd43f59ad7ceaf7c86b0fe4cdf261097e68b5c16a82c9892241bdcc0abc7a1d0", size = 35811, upload-time = "2025-11-30T19:19:21.767Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/80/4c88e4048b7d37f85e6b152da9327beb304562a27b7d2edc8c8550adf336/icalendar_searcher-1.0.3-py3-none-any.whl", hash = "sha256:66ab6d95a07039eb2d5f51821f6f0a981b97f43eaf16ff9c6835d6ae3ddd045b", size = 36093, upload-time = "2025-11-30T19:19:20.284Z" }, +] + +[[package]] +name = "icdiff" +version = "2.0.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fa/e4/43341832be5f2bcae71eb3ef08a07aaef9b74f74fe0b3675f62bd12057fe/icdiff-2.0.7.tar.gz", hash = "sha256:f79a318891adbf59a45e3a7694f5e1f18c5407065264637072ac8363b759866f", size = 16394, upload-time = "2023-08-21T15:00:55.742Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7c/2a/b3178baa75a3ec75a33588252296c82a1332d2b83cd01061539b74bde9dd/icdiff-2.0.7-py3-none-any.whl", hash = "sha256:f05d1b3623223dd1c70f7848da7d699de3d9a2550b902a8234d9026292fb5762", size = 17018, upload-time = "2023-08-21T15:00:54.634Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "inflection" +version = "0.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e1/7e/691d061b7329bc8d54edbf0ec22fbfb2afe61facb681f9aaa9bff7a27d04/inflection-0.5.1.tar.gz", hash = "sha256:1a29730d366e996aaacffb2f1f1cb9593dc38e2ddd30c91250c6dde09ea9b417", size = 15091, upload-time = "2020-08-22T08:16:29.139Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/59/91/aa6bde563e0085a02a435aa99b49ef75b0a4b062635e606dab23ce18d720/inflection-0.5.1-py2.py3-none-any.whl", hash = "sha256:f38b2b640938a4f35ade69ac3d053042959b62a0f1076a5bbaa1b9526605a8a2", size = 9454, upload-time = "2020-08-22T08:16:27.816Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" }, +] + +[[package]] +name = "ipdb" +version = "0.13.13" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "decorator" }, + { name = "ipython" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3d/1b/7e07e7b752017f7693a0f4d41c13e5ca29ce8cbcfdcc1fd6c4ad8c0a27a0/ipdb-0.13.13.tar.gz", hash = "sha256:e3ac6018ef05126d442af680aad863006ec19d02290561ac88b8b1c0b0cfc726", size = 17042, upload-time = "2023-03-09T15:40:57.487Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/4c/b075da0092003d9a55cf2ecc1cae9384a1ca4f650d51b00fc59875fe76f6/ipdb-0.13.13-py3-none-any.whl", hash = "sha256:45529994741c4ab6d2388bfa5d7b725c2cf7fe9deffabdb8a6113aa5ed449ed4", size = 12130, upload-time = "2023-03-09T15:40:55.021Z" }, +] + +[[package]] +name = "ipython" +version = "9.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/29/e6/48c74d54039241a456add616464ea28c6ebf782e4110d419411b83dae06f/ipython-9.7.0.tar.gz", hash = "sha256:5f6de88c905a566c6a9d6c400a8fed54a638e1f7543d17aae2551133216b1e4e", size = 4422115, upload-time = "2025-11-05T12:18:54.646Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/aa/62893d6a591d337aa59dcc4c6f6c842f1fe20cd72c8c5c1f980255243252/ipython-9.7.0-py3-none-any.whl", hash = "sha256:bce8ac85eb9521adc94e1845b4c03d88365fd6ac2f4908ec4ed1eb1b0a065f9f", size = 618911, upload-time = "2025-11-05T12:18:52.484Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "isort" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/82/fa43935523efdfcce6abbae9da7f372b627b27142c3419fcf13bf5b0c397/isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481", size = 824325, upload-time = "2025-10-01T16:26:45.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/cc/9b681a170efab4868a032631dea1e8446d8ec718a7f657b94d49d1a12643/isort-6.1.0-py3-none-any.whl", hash = "sha256:58d8927ecce74e5087aef019f778d4081a3b6c98f15a80ba35782ca8a2097784", size = 94329, upload-time = "2025-10-01T16:26:43.291Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jh2" +version = "5.0.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/ed/466eb2a162d9cfaa8452e9a05d24b4fc11d4cf84cf27f5a71457dc590323/jh2-5.0.10.tar.gz", hash = "sha256:2c737a47bee50dc727f7a766185e110befdceba5efb1c4fa240b1e4399291487", size = 7301475, upload-time = "2025-10-05T06:18:59.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/46/88/91e402bd0e323f3c7895d8eb6e79efe7d94bf40e035f6abcd9da0a08325c/jh2-5.0.10-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5a6885a315bdd24d822873d5e581eac90ab25589fb48d34f822352710139439a", size = 603894, upload-time = "2025-10-05T06:16:22.199Z" }, + { url = "https://files.pythonhosted.org/packages/3e/52/cdf454b01bdf7432848f7576b6054826fc65d77062324164995ff77a813d/jh2-5.0.10-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fa031e2aba9bd4cf6e1c0514764781b907557484cf163f02f1ad65a5932faf2", size = 378697, upload-time = "2025-10-05T06:16:24.128Z" }, + { url = "https://files.pythonhosted.org/packages/8e/dd/6e7106bc020e9fc13a70476c95cd4b40d2d301ef1c5ff7cd093adeec2143/jh2-5.0.10-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c816cfe85ae5d4fb26efc2713aedf9dfe1bb826544fe76cfd35ce7a60e099e8f", size = 390293, upload-time = "2025-10-05T06:16:25.723Z" }, + { url = "https://files.pythonhosted.org/packages/88/94/e64d83f8d2f5b7490e32d12f0ba3835b45b19d14af72ea592aacfb65592e/jh2-5.0.10-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b28c70b440f32bb8f14c3adaa11c094ea109fc1d2540434a8fc6e08cf4cf1aef", size = 524781, upload-time = "2025-10-05T06:16:27.382Z" }, + { url = "https://files.pythonhosted.org/packages/25/72/a2c72aff206bc27f3373982d318f305d31aca62dd5daa0c4e50c528208bb/jh2-5.0.10-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:df79bdf69d33ec0093c63abb633a6cbdb4b905a5ea3dda2514c4adf7e5713d20", size = 518173, upload-time = "2025-10-05T06:16:29.029Z" }, + { url = "https://files.pythonhosted.org/packages/26/27/e41b23fa62a0bbbf87cefdecbd938056a44b9c47a454a11edd760b92a9b3/jh2-5.0.10-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c0b7cda4b50692e2f259382fc2a374cd9118a96f8d369ef04fe088124f84fc", size = 409290, upload-time = "2025-10-05T06:16:30.628Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ed/516bdea8ff60bb321b92bac7d3b99a8aee322495e8b4dccc5b42eeede0b7/jh2-5.0.10-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ffeb6a352ce6c89d77bd185972185f20e3c35b3be4d0253963b6d8b6444c4aa", size = 386155, upload-time = "2025-10-05T06:16:31.898Z" }, + { url = "https://files.pythonhosted.org/packages/12/18/057408a548a66eb069c2fa12bfd13c1e34eaae07603f40ce32743ce0faa6/jh2-5.0.10-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:271720035a1293031c807e24a27235a2426c51de8755db872eb1adad310213cd", size = 403861, upload-time = "2025-10-05T06:16:33.036Z" }, + { url = "https://files.pythonhosted.org/packages/3d/70/73d22e62af0e756cb3b86ee57b67b117efe75091d56ff286bf136adde863/jh2-5.0.10-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:7b28fc12106654573881f19b1a78e41cf37657ae76efa84e7da518faced56f0f", size = 559909, upload-time = "2025-10-05T06:16:34.262Z" }, + { url = "https://files.pythonhosted.org/packages/66/fa/5d5e4304ecfa27773bbe036454b782882fc2ab02f7521ae0d367514c7618/jh2-5.0.10-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:976134b61b7fdf290a7cc70e7676c2605af84dd83e2a1e78c170928a0119278b", size = 653300, upload-time = "2025-10-05T06:16:35.825Z" }, + { url = "https://files.pythonhosted.org/packages/dc/b4/31583a8bcbe58ee13b30bdf9d82ca52a3272a13c45384bf8e193a2e4541f/jh2-5.0.10-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:75581b5acbcc344e070f811938919165999bf7221406845306e0ab860605cdbf", size = 580061, upload-time = "2025-10-05T06:16:37.598Z" }, + { url = "https://files.pythonhosted.org/packages/66/3e/ffcc082b72c7f83512cc1dbda866afa5c0dbd76c423e6f0294496744af27/jh2-5.0.10-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:206e4a92c687f6928b3846d7666ebf2602c16556feb154f16f1d399219046f5d", size = 550849, upload-time = "2025-10-05T06:16:38.887Z" }, + { url = "https://files.pythonhosted.org/packages/19/da/01f0df3a779d0d2e8b7ce121da48b1a91346264fd494c0be16a74e5c1c4f/jh2-5.0.10-cp313-cp313t-win32.whl", hash = "sha256:fca31a36827205c76c959be94e8bad7aaa1be06ea8ed904b20b5d96a7829ce45", size = 234414, upload-time = "2025-10-05T06:16:40.509Z" }, + { url = "https://files.pythonhosted.org/packages/82/c1/42a68cbe4c6ee9453d3685bd4ebce8e3bccbda608b3c26f380cf30640825/jh2-5.0.10-cp313-cp313t-win_amd64.whl", hash = "sha256:4bbefb69efaa365f3193d0db096d34e9e0da5885b0bb1341ab7593852e811f69", size = 241768, upload-time = "2025-10-05T06:16:41.701Z" }, + { url = "https://files.pythonhosted.org/packages/10/14/4d89e958e2a98ee09895290a105caee5cd158fb456fc9aae913f15251184/jh2-5.0.10-cp313-cp313t-win_arm64.whl", hash = "sha256:9752ea045ab3da4544104201a800d3f7ce7c63b529db5a9715c587cbfedca9b7", size = 237090, upload-time = "2025-10-05T06:16:43.228Z" }, + { url = "https://files.pythonhosted.org/packages/63/8f/fe337b9104ab3a444a7b20baffc3dd54f3227a44f3037aba2a30bf36fefd/jh2-5.0.10-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:7c2918379cce3352b6d40717ed3d5b06da6e6c17253317302cab2f0dbff62a5d", size = 622842, upload-time = "2025-10-05T06:17:06.121Z" }, + { url = "https://files.pythonhosted.org/packages/63/37/f3c59f62e771755b31b6d1ce9124d4ab40bc3a2206116bfd879a33c1b02f/jh2-5.0.10-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd229bbe7dfdf499394fa8453c92e2ea19de47c80afc1efaec7f85704be97717", size = 385674, upload-time = "2025-10-05T06:17:07.369Z" }, + { url = "https://files.pythonhosted.org/packages/03/9d/719cfd3afab6bb9115f574687fa24ea5731267ee9701439e30e06a45f468/jh2-5.0.10-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:36e9b5fb9cd8872846d031fae442df1b5c83f4dd29ef1dd1c3f70afd86fe8fc3", size = 396276, upload-time = "2025-10-05T06:17:08.933Z" }, + { url = "https://files.pythonhosted.org/packages/22/63/1f36ff610684f2cb177218c700d3a3f4f87aad4d45a6e3f59feb360812c6/jh2-5.0.10-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:217af8256551627b9253737a866c05ce5f6c49f171c099260b76915239cfb13a", size = 532742, upload-time = "2025-10-05T06:17:10.396Z" }, + { url = "https://files.pythonhosted.org/packages/59/c5/063fe0b930c0b15e8c0376d9d6cc20dcc3179823e6f456c1a571db1d27c4/jh2-5.0.10-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e20e3d747c4022d890865fb25f2e8b3ff6cbacf7556f29155dcfbff592d96202", size = 525320, upload-time = "2025-10-05T06:17:12.187Z" }, + { url = "https://files.pythonhosted.org/packages/e8/7a/c1f4a961554f6b521bfc75320264c0bde50210c11a206719e0c98c17e617/jh2-5.0.10-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6ea77b8b6b7defb67cbec69340e653495b36881671e9f0ac395cdd6b27144000", size = 416184, upload-time = "2025-10-05T06:17:13.428Z" }, + { url = "https://files.pythonhosted.org/packages/37/c9/75fdfd2ef673accba9b1ace28ffa2aaced23fba3209ac73521e441ae2265/jh2-5.0.10-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3fd6b5b2d4d38e089ac982ea341b36f2cb827c0765217e6b8f3e58a409290e6f", size = 394145, upload-time = "2025-10-05T06:17:14.673Z" }, + { url = "https://files.pythonhosted.org/packages/52/5e/38b1b14182afcebf89d542b7a2e4cd4d7deaf9e4cae0a45b0a85115f0da7/jh2-5.0.10-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4c3d38121a1ddc2ffc769f09aaaa4c7e67f89e25c578921326b515402176e7cf", size = 411333, upload-time = "2025-10-05T06:17:15.913Z" }, + { url = "https://files.pythonhosted.org/packages/a8/04/10383a467f24d2643013f784bca4ddb81dc9d0d81641a846b71bd0aa64e0/jh2-5.0.10-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:33e4ac058acf8f3f89ea1375deb33ac61713d60fb9e3333bd079f3602425739c", size = 565892, upload-time = "2025-10-05T06:17:17.517Z" }, + { url = "https://files.pythonhosted.org/packages/9d/1a/b416bd65176593b405320bfd763ddc9cae3941fe96c7055ec1c46e081ebd/jh2-5.0.10-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:86571f18274d7a5a7e6406e156a9f27fa1a72203a176921ea234c4a11fe0e105", size = 659878, upload-time = "2025-10-05T06:17:18.972Z" }, + { url = "https://files.pythonhosted.org/packages/a9/2d/e4c3b90585e92676777e9bcb9218ce97552f0c9797cec142d549904ca67b/jh2-5.0.10-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:62f0842b5f8da463b6a548a8c2a7e69fa709888d03c997486390097341e88e09", size = 587129, upload-time = "2025-10-05T06:17:20.669Z" }, + { url = "https://files.pythonhosted.org/packages/98/d5/3e89d65bb6bbcdaa14236e9ec8f643cf77a5809d7315ce1208f0ef53927c/jh2-5.0.10-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:f3b6401f089a65b87f2e5beffe81666a1c2ab1d90e8406cd49c756d66881bedc", size = 556811, upload-time = "2025-10-05T06:17:22.37Z" }, + { url = "https://files.pythonhosted.org/packages/7d/8c/a05403065463ef759059d75e0862c94aa60d2019a7dcd41d716f6d8d6c32/jh2-5.0.10-cp37-abi3-win32.whl", hash = "sha256:7b79771bd366a11a36041f49cabc7876047cf1b99cee89df1333e6890f66d973", size = 239474, upload-time = "2025-10-05T06:17:23.637Z" }, + { url = "https://files.pythonhosted.org/packages/96/ac/92f97f07f748bdc9280c5d50e787773bef188c29c32f6804f2fc72cca725/jh2-5.0.10-cp37-abi3-win_amd64.whl", hash = "sha256:9c730e3f40f22bd4ff0ab63ee41d70ee22aa1cc54e5cb295ae0ac3b0a016af3e", size = 246320, upload-time = "2025-10-05T06:17:25.313Z" }, + { url = "https://files.pythonhosted.org/packages/f0/ad/e9f4035ddd847efe26914da64f9d54198bf5b0bdcfd0e8bbcf6a328e1f7c/jh2-5.0.10-cp37-abi3-win_arm64.whl", hash = "sha256:d18eccec757374afca8de31bf012a888fb82903d5803e84f2e6f0b707478ced6", size = 241790, upload-time = "2025-10-05T06:17:26.488Z" }, + { url = "https://files.pythonhosted.org/packages/93/57/d0fcb025736e24cb68c4e250cc4cf63a87b7e0bd7285e188c543018d05c1/jh2-5.0.10-py3-none-any.whl", hash = "sha256:1808c0e5d355c60485bb282b34c6aa3f15069b2634eb44779fb9f3bda0256ac0", size = 98099, upload-time = "2025-10-05T06:18:58.203Z" }, +] + +[[package]] +name = "josepy" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7f/ad/6f520aee9cc9618d33430380741e9ef859b2c560b1e7915e755c084f6bc0/josepy-2.2.0.tar.gz", hash = "sha256:74c033151337c854f83efe5305a291686cef723b4b970c43cfe7270cf4a677a9", size = 56500, upload-time = "2025-10-14T14:54:42.108Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/b2/b5caed897fbb1cc286c62c01feca977e08d99a17230ff3055b9a98eccf1d/josepy-2.2.0-py3-none-any.whl", hash = "sha256:63e9dd116d4078778c25ca88f880cc5d95f1cab0099bebe3a34c2e299f65d10b", size = 29211, upload-time = "2025-10-14T14:54:41.144Z" }, +] + +[[package]] +name = "joserfc" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/a0/e77842f16d07ef8d23faf9cf675f2f5b358b093253b41b53f6214a52e5e7/joserfc-1.6.0.tar.gz", hash = "sha256:27946ee53f591c2da65b726a663a68f0fb000732eaadfe819bbbda6429702ad0", size = 225982, upload-time = "2025-12-14T05:20:38.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ac/2b/94a31afef483ea5ac05c3545defed42704e941713dff5d9dbe5212ad5452/joserfc-1.6.0-py3-none-any.whl", hash = "sha256:14ed0d9cef03aa9332452cbcc59ff31c8c7b3f9737401a9ead3009c2a914bf54", size = 70259, upload-time = "2025-12-14T05:20:37.238Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/19/74/a633ee74eb36c44aa6d1095e7cc5569bebf04342ee146178e2d36600708b/jsonschema_specifications-2025.9.1.tar.gz", hash = "sha256:b540987f239e745613c7a9176f3edb72b832a4ac465cf02712288397832b5e8d", size = 32855, upload-time = "2025-09-08T01:34:59.186Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/45/1a4ed80516f02155c51f51e8cedb3c1902296743db0bbc66608a0db2814f/jsonschema_specifications-2025.9.1-py3-none-any.whl", hash = "sha256:98802fee3a11ee76ecaca44429fda8a41bff98b00a0f2838151b113f210cc6fe", size = 18437, upload-time = "2025-09-08T01:34:57.871Z" }, +] + +[[package]] +name = "kombu" +version = "5.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "amqp" }, + { name = "packaging" }, + { name = "tzdata" }, + { name = "vine" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ac/05/749ada8e51718445d915af13f1d18bc4333848e8faa0cb234028a3328ec8/kombu-5.6.1.tar.gz", hash = "sha256:90f1febb57ad4f53ca327a87598191b2520e0c793c75ea3b88d98e3b111282e4", size = 471548, upload-time = "2025-11-25T11:07:33.504Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/d6/943cf84117cd9ddecf6e1707a3f712a49fc64abdb8ac31b19132871af1dd/kombu-5.6.1-py3-none-any.whl", hash = "sha256:b69e3f5527ec32fc5196028a36376501682973e9620d6175d1c3d4eaf7e95409", size = 214141, upload-time = "2025-11-25T11:07:31.54Z" }, +] + +[package.optional-dependencies] +redis = [ + { name = "redis" }, +] + +[[package]] +name = "lxml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/88/262177de60548e5a2bfc46ad28232c9e9cbde697bd94132aeb80364675cb/lxml-6.0.2.tar.gz", hash = "sha256:cd79f3367bd74b317dda655dc8fcfa304d9eb6e4fb06b7168c5cf27f96e0cd62", size = 4073426, upload-time = "2025-09-22T04:04:59.287Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/fd/4e8f0540608977aea078bf6d79f128e0e2c2bba8af1acf775c30baa70460/lxml-6.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9b33d21594afab46f37ae58dfadd06636f154923c4e8a4d754b0127554eb2e77", size = 8648494, upload-time = "2025-09-22T04:01:54.242Z" }, + { url = "https://files.pythonhosted.org/packages/5d/f4/2a94a3d3dfd6c6b433501b8d470a1960a20ecce93245cf2db1706adf6c19/lxml-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6c8963287d7a4c5c9a432ff487c52e9c5618667179c18a204bdedb27310f022f", size = 4661146, upload-time = "2025-09-22T04:01:56.282Z" }, + { url = "https://files.pythonhosted.org/packages/25/2e/4efa677fa6b322013035d38016f6ae859d06cac67437ca7dc708a6af7028/lxml-6.0.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:1941354d92699fb5ffe6ed7b32f9649e43c2feb4b97205f75866f7d21aa91452", size = 4946932, upload-time = "2025-09-22T04:01:58.989Z" }, + { url = "https://files.pythonhosted.org/packages/ce/0f/526e78a6d38d109fdbaa5049c62e1d32fdd70c75fb61c4eadf3045d3d124/lxml-6.0.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:bb2f6ca0ae2d983ded09357b84af659c954722bbf04dea98030064996d156048", size = 5100060, upload-time = "2025-09-22T04:02:00.812Z" }, + { url = "https://files.pythonhosted.org/packages/81/76/99de58d81fa702cc0ea7edae4f4640416c2062813a00ff24bd70ac1d9c9b/lxml-6.0.2-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb2a12d704f180a902d7fa778c6d71f36ceb7b0d317f34cdc76a5d05aa1dd1df", size = 5019000, upload-time = "2025-09-22T04:02:02.671Z" }, + { url = "https://files.pythonhosted.org/packages/b5/35/9e57d25482bc9a9882cb0037fdb9cc18f4b79d85df94fa9d2a89562f1d25/lxml-6.0.2-cp313-cp313-manylinux_2_26_i686.manylinux_2_28_i686.whl", hash = "sha256:6ec0e3f745021bfed19c456647f0298d60a24c9ff86d9d051f52b509663feeb1", size = 5348496, upload-time = "2025-09-22T04:02:04.904Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8e/cb99bd0b83ccc3e8f0f528e9aa1f7a9965dfec08c617070c5db8d63a87ce/lxml-6.0.2-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:846ae9a12d54e368933b9759052d6206a9e8b250291109c48e350c1f1f49d916", size = 5643779, upload-time = "2025-09-22T04:02:06.689Z" }, + { url = "https://files.pythonhosted.org/packages/d0/34/9e591954939276bb679b73773836c6684c22e56d05980e31d52a9a8deb18/lxml-6.0.2-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ef9266d2aa545d7374938fb5c484531ef5a2ec7f2d573e62f8ce722c735685fd", size = 5244072, upload-time = "2025-09-22T04:02:08.587Z" }, + { url = "https://files.pythonhosted.org/packages/8d/27/b29ff065f9aaca443ee377aff699714fcbffb371b4fce5ac4ca759e436d5/lxml-6.0.2-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:4077b7c79f31755df33b795dc12119cb557a0106bfdab0d2c2d97bd3cf3dffa6", size = 4718675, upload-time = "2025-09-22T04:02:10.783Z" }, + { url = "https://files.pythonhosted.org/packages/2b/9f/f756f9c2cd27caa1a6ef8c32ae47aadea697f5c2c6d07b0dae133c244fbe/lxml-6.0.2-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a7c5d5e5f1081955358533be077166ee97ed2571d6a66bdba6ec2f609a715d1a", size = 5255171, upload-time = "2025-09-22T04:02:12.631Z" }, + { url = "https://files.pythonhosted.org/packages/61/46/bb85ea42d2cb1bd8395484fd72f38e3389611aa496ac7772da9205bbda0e/lxml-6.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:8f8d0cbd0674ee89863a523e6994ac25fd5be9c8486acfc3e5ccea679bad2679", size = 5057175, upload-time = "2025-09-22T04:02:14.718Z" }, + { url = "https://files.pythonhosted.org/packages/95/0c/443fc476dcc8e41577f0af70458c50fe299a97bb6b7505bb1ae09aa7f9ac/lxml-6.0.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:2cbcbf6d6e924c28f04a43f3b6f6e272312a090f269eff68a2982e13e5d57659", size = 4785688, upload-time = "2025-09-22T04:02:16.957Z" }, + { url = "https://files.pythonhosted.org/packages/48/78/6ef0b359d45bb9697bc5a626e1992fa5d27aa3f8004b137b2314793b50a0/lxml-6.0.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dfb874cfa53340009af6bdd7e54ebc0d21012a60a4e65d927c2e477112e63484", size = 5660655, upload-time = "2025-09-22T04:02:18.815Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ea/e1d33808f386bc1339d08c0dcada6e4712d4ed8e93fcad5f057070b7988a/lxml-6.0.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:fb8dae0b6b8b7f9e96c26fdd8121522ce5de9bb5538010870bd538683d30e9a2", size = 5247695, upload-time = "2025-09-22T04:02:20.593Z" }, + { url = "https://files.pythonhosted.org/packages/4f/47/eba75dfd8183673725255247a603b4ad606f4ae657b60c6c145b381697da/lxml-6.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:358d9adae670b63e95bc59747c72f4dc97c9ec58881d4627fe0120da0f90d314", size = 5269841, upload-time = "2025-09-22T04:02:22.489Z" }, + { url = "https://files.pythonhosted.org/packages/76/04/5c5e2b8577bc936e219becb2e98cdb1aca14a4921a12995b9d0c523502ae/lxml-6.0.2-cp313-cp313-win32.whl", hash = "sha256:e8cd2415f372e7e5a789d743d133ae474290a90b9023197fd78f32e2dc6873e2", size = 3610700, upload-time = "2025-09-22T04:02:24.465Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0a/4643ccc6bb8b143e9f9640aa54e38255f9d3b45feb2cbe7ae2ca47e8782e/lxml-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:b30d46379644fbfc3ab81f8f82ae4de55179414651f110a1514f0b1f8f6cb2d7", size = 4010347, upload-time = "2025-09-22T04:02:26.286Z" }, + { url = "https://files.pythonhosted.org/packages/31/ef/dcf1d29c3f530577f61e5fe2f1bd72929acf779953668a8a47a479ae6f26/lxml-6.0.2-cp313-cp313-win_arm64.whl", hash = "sha256:13dcecc9946dca97b11b7c40d29fba63b55ab4170d3c0cf8c0c164343b9bfdcf", size = 3671248, upload-time = "2025-09-22T04:02:27.918Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/74/97e72a36efd4ae2bccb3463284300f8953f199b5ffbc04cbbb0ec78f74b1/matplotlib_inline-0.2.1.tar.gz", hash = "sha256:e1ee949c340d771fc39e241ea75683deb94762c8fa5f2927ec57c83c4dffa9fe", size = 8110, upload-time = "2025-10-23T09:00:22.126Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/33/ee4519fa02ed11a94aef9559552f3b17bb863f2ecfe1a35dc7f548cde231/matplotlib_inline-0.2.1-py3-none-any.whl", hash = "sha256:d56ce5156ba6085e00a9d54fead6ed29a9c47e215cd1bba2e976ef39f5710a76", size = 9516, upload-time = "2025-10-23T09:00:20.675Z" }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, +] + +[[package]] +name = "mozilla-django-oidc" +version = "4.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cryptography" }, + { name = "django" }, + { name = "josepy" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/90/f9/1ca554a62bf8a4fd31b68209df8603075c2b7436400ea3f7ddd597f204a5/mozilla-django-oidc-4.0.1.tar.gz", hash = "sha256:4ff8c64069e3e05c539cecf9345e73225a99641a25e13b7a5f933ec897b58918", size = 49027, upload-time = "2024-03-12T12:29:26.866Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/d6/2b75bf4e742c54028ae07a1fb5a2624e5a73e9cfd2185c2df0e22cbfe14e/mozilla_django_oidc-4.0.1-py2.py3-none-any.whl", hash = "sha256:04ef58759be69f22cdc402d082480aaebf193466cad385dc9e4f8df2a0b187ca", size = 29059, upload-time = "2024-03-12T12:29:24.978Z" }, +] + +[[package]] +name = "nested-multipart-parser" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/48/b91a6f924a2abd9e86b501347ca56989e2c2b4bf3eac86bff57f80b99b75/nested_multipart_parser-1.6.0.tar.gz", hash = "sha256:8c7a07952a4a3c2cb2b99ca16158961af215c6f8c9e04337bc13da016500c69c", size = 13159, upload-time = "2025-09-17T20:47:25.627Z" } + +[[package]] +name = "niquests" +version = "3.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "charset-normalizer" }, + { name = "urllib3-future" }, + { name = "wassima" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/09/95/39d0917de33ce1ebec27fa00660df9faad7608de14eaf7fc3bf43d84d3c4/niquests-3.16.1.tar.gz", hash = "sha256:0750eb7fb4bdf46af5041e75c5f37a2a6974e6f620b0f6a234c4b858dbf38ddb", size = 981092, upload-time = "2025-12-23T16:42:09.548Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f4/c5/0d136dac4051352da613e8676743dad21d41578832d622d3b4db7a103967/niquests-3.16.1-py3-none-any.whl", hash = "sha256:e26e302f36fb6730f9c36755506a84a5f2bb1ae92c7ef5029a6cc7cf98622ded", size = 170850, upload-time = "2025-12-23T16:42:08.072Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parso" +version = "0.8.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d4/de/53e0bcf53d13e005bd8c92e7855142494f41171b34c2536b86187474184d/parso-0.8.5.tar.gz", hash = "sha256:034d7354a9a018bdce352f48b2a8a450f05e9d6ee85db84764e9b6bd96dafe5a", size = 401205, upload-time = "2025-08-23T15:15:28.028Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/16/32/f8e3c85d1d5250232a5d3477a2a28cc291968ff175caeadaf3cc19ce0e4a/parso-0.8.5-py2.py3-none-any.whl", hash = "sha256:646204b5ee239c396d040b90f9e272e9a8017c630092bf59980beb62fd033887", size = 106668, upload-time = "2025-08-23T15:15:25.663Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "pillow" +version = "12.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/f2/de993bb2d21b33a98d031ecf6a978e4b61da207bef02f7b43093774c480d/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:0869154a2d0546545cde61d1789a6524319fc1897d9ee31218eae7a60ccc5643", size = 4045493, upload-time = "2025-10-15T18:22:25.758Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b6/bc8d0c4c9f6f111a783d045310945deb769b806d7574764234ffd50bc5ea/pillow-12.0.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:a7921c5a6d31b3d756ec980f2f47c0cfdbce0fc48c22a39347a895f41f4a6ea4", size = 4120461, upload-time = "2025-10-15T18:22:27.286Z" }, + { url = "https://files.pythonhosted.org/packages/5d/57/d60d343709366a353dc56adb4ee1e7d8a2cc34e3fbc22905f4167cfec119/pillow-12.0.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:1ee80a59f6ce048ae13cda1abf7fbd2a34ab9ee7d401c46be3ca685d1999a399", size = 3576912, upload-time = "2025-10-15T18:22:28.751Z" }, + { url = "https://files.pythonhosted.org/packages/a4/a4/a0a31467e3f83b94d37568294b01d22b43ae3c5d85f2811769b9c66389dd/pillow-12.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c50f36a62a22d350c96e49ad02d0da41dbd17ddc2e29750dbdba4323f85eb4a5", size = 5249132, upload-time = "2025-10-15T18:22:30.641Z" }, + { url = "https://files.pythonhosted.org/packages/83/06/48eab21dd561de2914242711434c0c0eb992ed08ff3f6107a5f44527f5e9/pillow-12.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5193fde9a5f23c331ea26d0cf171fbf67e3f247585f50c08b3e205c7aeb4589b", size = 4650099, upload-time = "2025-10-15T18:22:32.73Z" }, + { url = "https://files.pythonhosted.org/packages/fc/bd/69ed99fd46a8dba7c1887156d3572fe4484e3f031405fcc5a92e31c04035/pillow-12.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bde737cff1a975b70652b62d626f7785e0480918dece11e8fef3c0cf057351c3", size = 6230808, upload-time = "2025-10-15T18:22:34.337Z" }, + { url = "https://files.pythonhosted.org/packages/ea/94/8fad659bcdbf86ed70099cb60ae40be6acca434bbc8c4c0d4ef356d7e0de/pillow-12.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a6597ff2b61d121172f5844b53f21467f7082f5fb385a9a29c01414463f93b07", size = 8037804, upload-time = "2025-10-15T18:22:36.402Z" }, + { url = "https://files.pythonhosted.org/packages/20/39/c685d05c06deecfd4e2d1950e9a908aa2ca8bc4e6c3b12d93b9cafbd7837/pillow-12.0.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0b817e7035ea7f6b942c13aa03bb554fc44fea70838ea21f8eb31c638326584e", size = 6345553, upload-time = "2025-10-15T18:22:38.066Z" }, + { url = "https://files.pythonhosted.org/packages/38/57/755dbd06530a27a5ed74f8cb0a7a44a21722ebf318edbe67ddbd7fb28f88/pillow-12.0.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f4f1231b7dec408e8670264ce63e9c71409d9583dd21d32c163e25213ee2a344", size = 7037729, upload-time = "2025-10-15T18:22:39.769Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b6/7e94f4c41d238615674d06ed677c14883103dce1c52e4af16f000338cfd7/pillow-12.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6e51b71417049ad6ab14c49608b4a24d8fb3fe605e5dfabfe523b58064dc3d27", size = 6459789, upload-time = "2025-10-15T18:22:41.437Z" }, + { url = "https://files.pythonhosted.org/packages/9c/14/4448bb0b5e0f22dd865290536d20ec8a23b64e2d04280b89139f09a36bb6/pillow-12.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d120c38a42c234dc9a8c5de7ceaaf899cf33561956acb4941653f8bdc657aa79", size = 7130917, upload-time = "2025-10-15T18:22:43.152Z" }, + { url = "https://files.pythonhosted.org/packages/dd/ca/16c6926cc1c015845745d5c16c9358e24282f1e588237a4c36d2b30f182f/pillow-12.0.0-cp313-cp313-win32.whl", hash = "sha256:4cc6b3b2efff105c6a1656cfe59da4fdde2cda9af1c5e0b58529b24525d0a098", size = 6302391, upload-time = "2025-10-15T18:22:44.753Z" }, + { url = "https://files.pythonhosted.org/packages/6d/2a/dd43dcfd6dae9b6a49ee28a8eedb98c7d5ff2de94a5d834565164667b97b/pillow-12.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:4cf7fed4b4580601c4345ceb5d4cbf5a980d030fd5ad07c4d2ec589f95f09905", size = 7007477, upload-time = "2025-10-15T18:22:46.838Z" }, + { url = "https://files.pythonhosted.org/packages/77/f0/72ea067f4b5ae5ead653053212af05ce3705807906ba3f3e8f58ddf617e6/pillow-12.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:9f0b04c6b8584c2c193babcccc908b38ed29524b29dd464bc8801bf10d746a3a", size = 2435918, upload-time = "2025-10-15T18:22:48.399Z" }, + { url = "https://files.pythonhosted.org/packages/f5/5e/9046b423735c21f0487ea6cb5b10f89ea8f8dfbe32576fe052b5ba9d4e5b/pillow-12.0.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:7fa22993bac7b77b78cae22bad1e2a987ddf0d9015c63358032f84a53f23cdc3", size = 5251406, upload-time = "2025-10-15T18:22:49.905Z" }, + { url = "https://files.pythonhosted.org/packages/12/66/982ceebcdb13c97270ef7a56c3969635b4ee7cd45227fa707c94719229c5/pillow-12.0.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f135c702ac42262573fe9714dfe99c944b4ba307af5eb507abef1667e2cbbced", size = 4653218, upload-time = "2025-10-15T18:22:51.587Z" }, + { url = "https://files.pythonhosted.org/packages/16/b3/81e625524688c31859450119bf12674619429cab3119eec0e30a7a1029cb/pillow-12.0.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:c85de1136429c524e55cfa4e033b4a7940ac5c8ee4d9401cc2d1bf48154bbc7b", size = 6266564, upload-time = "2025-10-15T18:22:53.215Z" }, + { url = "https://files.pythonhosted.org/packages/98/59/dfb38f2a41240d2408096e1a76c671d0a105a4a8471b1871c6902719450c/pillow-12.0.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:38df9b4bfd3db902c9c2bd369bcacaf9d935b2fff73709429d95cc41554f7b3d", size = 8069260, upload-time = "2025-10-15T18:22:54.933Z" }, + { url = "https://files.pythonhosted.org/packages/dc/3d/378dbea5cd1874b94c312425ca77b0f47776c78e0df2df751b820c8c1d6c/pillow-12.0.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7d87ef5795da03d742bf49439f9ca4d027cde49c82c5371ba52464aee266699a", size = 6379248, upload-time = "2025-10-15T18:22:56.605Z" }, + { url = "https://files.pythonhosted.org/packages/84/b0/d525ef47d71590f1621510327acec75ae58c721dc071b17d8d652ca494d8/pillow-12.0.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aff9e4d82d082ff9513bdd6acd4f5bd359f5b2c870907d2b0a9c5e10d40c88fe", size = 7066043, upload-time = "2025-10-15T18:22:58.53Z" }, + { url = "https://files.pythonhosted.org/packages/61/2c/aced60e9cf9d0cde341d54bf7932c9ffc33ddb4a1595798b3a5150c7ec4e/pillow-12.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:8d8ca2b210ada074d57fcee40c30446c9562e542fc46aedc19baf758a93532ee", size = 6490915, upload-time = "2025-10-15T18:23:00.582Z" }, + { url = "https://files.pythonhosted.org/packages/ef/26/69dcb9b91f4e59f8f34b2332a4a0a951b44f547c4ed39d3e4dcfcff48f89/pillow-12.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:99a7f72fb6249302aa62245680754862a44179b545ded638cf1fef59befb57ef", size = 7157998, upload-time = "2025-10-15T18:23:02.627Z" }, + { url = "https://files.pythonhosted.org/packages/61/2b/726235842220ca95fa441ddf55dd2382b52ab5b8d9c0596fe6b3f23dafe8/pillow-12.0.0-cp313-cp313t-win32.whl", hash = "sha256:4078242472387600b2ce8d93ade8899c12bf33fa89e55ec89fe126e9d6d5d9e9", size = 6306201, upload-time = "2025-10-15T18:23:04.709Z" }, + { url = "https://files.pythonhosted.org/packages/c0/3d/2afaf4e840b2df71344ababf2f8edd75a705ce500e5dc1e7227808312ae1/pillow-12.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:2c54c1a783d6d60595d3514f0efe9b37c8808746a66920315bfd34a938d7994b", size = 7013165, upload-time = "2025-10-15T18:23:06.46Z" }, + { url = "https://files.pythonhosted.org/packages/6f/75/3fa09aa5cf6ed04bee3fa575798ddf1ce0bace8edb47249c798077a81f7f/pillow-12.0.0-cp313-cp313t-win_arm64.whl", hash = "sha256:26d9f7d2b604cd23aba3e9faf795787456ac25634d82cd060556998e39c6fa47", size = 2437834, upload-time = "2025-10-15T18:23:08.194Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.5.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cf/86/0248f086a84f01b37aaec0fa567b397df1a119f73c16f6c7a9aac73ea309/platformdirs-4.5.1.tar.gz", hash = "sha256:61d5cdcc6065745cdd94f0f878977f8de9437be93de97c1c12f853c9c0cdcbda", size = 21715, upload-time = "2025-12-05T13:52:58.638Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/28/3bfe2fa5a7b9c46fe7e13c97bda14c895fb10fa2ebf1d0abb90e0cea7ee1/platformdirs-4.5.1-py3-none-any.whl", hash = "sha256:d03afa3963c806a9bed9d5125c8f4cb2fdaf74a55ab60e5d59b3fde758104d31", size = 18731, upload-time = "2025-12-05T13:52:56.823Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "pprintpp" +version = "0.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/06/1a/7737e7a0774da3c3824d654993cf57adc915cb04660212f03406334d8c0b/pprintpp-0.4.0.tar.gz", hash = "sha256:ea826108e2c7f49dc6d66c752973c3fc9749142a798d6b254e1e301cfdbc6403", size = 17995, upload-time = "2018-07-01T01:42:34.87Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/d1/e4ed95fdd3ef13b78630280d9e9e240aeb65cc7c544ec57106149c3942fb/pprintpp-0.4.0-py2.py3-none-any.whl", hash = "sha256:b6b4dcdd0c0c0d75e4d7b2f21a9e933e5b2ce62b26e1a54537f9651ae5a5c01d", size = 16952, upload-time = "2018-07-01T01:42:36.496Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.52" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a1/96/06e01a7b38dce6fe1db213e061a4602dd6032a8a97ef6c1a862537732421/prompt_toolkit-3.0.52.tar.gz", hash = "sha256:28cde192929c8e7321de85de1ddbe736f1375148b02f2e17edd840042b1be855", size = 434198, upload-time = "2025-08-27T15:24:02.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/03/0d3ce49e2505ae70cf43bc5bb3033955d2fc9f932163e84dc0779cc47f48/prompt_toolkit-3.0.52-py3-none-any.whl", hash = "sha256:9aac639a3bbd33284347de5ad8d68ecc044b91a762dc39b7c21095fcd6a19955", size = 391431, upload-time = "2025-08-27T15:23:59.498Z" }, +] + +[[package]] +name = "psycopg" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/18/ed/3a30e8ef82d4128c76aa9bd6b2a7fe6c16c283811e6655997f5047801b47/psycopg-3.3.1.tar.gz", hash = "sha256:ccfa30b75874eef809c0fbbb176554a2640cc1735a612accc2e2396a92442fc6", size = 165596, upload-time = "2025-12-02T21:09:55.545Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b6/f3/0b4a4c25a47c2d907afa97674287dab61bc9941c9ac3972a67100e33894d/psycopg-3.3.1-py3-none-any.whl", hash = "sha256:e44d8eae209752efe46318f36dd0fdf5863e928009338d736843bb1084f6435c", size = 212760, upload-time = "2025-12-02T21:02:36.029Z" }, +] + +[package.optional-dependencies] +binary = [ + { name = "psycopg-binary", marker = "implementation_name != 'pypy'" }, +] + +[[package]] +name = "psycopg-binary" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/44/f907c508267bc203082217faf5750274f4c240471f99990db70ed9f4dada/psycopg_binary-3.3.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:fda22ce8530236381ff79a674ebc319f1a224f2e39a44158774e55e1488f89b9", size = 4579070, upload-time = "2025-12-02T21:08:04.885Z" }, + { url = "https://files.pythonhosted.org/packages/08/61/554bd7b9b93aef79f0bd3c4d381d9809ecf38e55ab4eb5984f58a74695f7/psycopg_binary-3.3.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d2fc5fa6c45c406e43c8cc2787055d487b3ae597d2139125191b37fa04835f01", size = 4657517, upload-time = "2025-12-02T21:08:08.941Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1b/c3bc20b72b9b056d1f7a3a131d676c66fe2bc7585f9d9f23d659d8725407/psycopg_binary-3.3.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4d97e4d27cc7ee6938faf7dc9919c452581b4795bd97f3f48582846f24ab81ed", size = 5452087, upload-time = "2025-12-02T21:08:15.144Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e6/58ae55874b963893f46d68748b28e05c432b0c109f53b40970ba6bf9fe95/psycopg_binary-3.3.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f4fb5a3cf4373a8b06c2feb8f29ff4c69968ba443687dedec9f79ce22ef339ae", size = 5131126, upload-time = "2025-12-02T21:08:23.463Z" }, + { url = "https://files.pythonhosted.org/packages/4c/28/bfcfb1b7c2907585292aaf61e902cbd00ecff50120178bc3e8268a74c1d6/psycopg_binary-3.3.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4de5298b81423648ae751c789a6adb7f9396bd4de7f402db8f469901d676ebe4", size = 6722913, upload-time = "2025-12-02T21:08:30.328Z" }, + { url = "https://files.pythonhosted.org/packages/c5/ba/7f6d3117059d4824854fb4eeafe7cb9fe069a43724f6a36b21aac0cd911d/psycopg_binary-3.3.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a41139976b8546b78ccd776b9f63665c247e209ae384fa6908ea401e9df2c385", size = 4966088, upload-time = "2025-12-02T21:08:34.666Z" }, + { url = "https://files.pythonhosted.org/packages/a5/18/d1baed589d7254be32eda44262787e397d1845fc7f08a30c38bf9345d361/psycopg_binary-3.3.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f8ea017e58fa7fd8df1d9058ff0248e28f29312bf150a00114fc0ace8a800bfa", size = 4493332, upload-time = "2025-12-02T21:08:38.935Z" }, + { url = "https://files.pythonhosted.org/packages/08/62/57c6ac97cd4d1297115c3840fe09a19ae50b96294e3b8e988385497dc074/psycopg_binary-3.3.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:447e31350ea6816af03f39e6fc5ccccf18e34dc223a7d82734621048bb3fb9af", size = 4170782, upload-time = "2025-12-02T21:08:43.949Z" }, + { url = "https://files.pythonhosted.org/packages/12/27/b2577aad1baaa476cf482fb207850fb3f03467b3e6f3485e8cf360588ea8/psycopg_binary-3.3.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:1f97f1814b046c8103b0a46a8c36c28399489716eba70ed38fbae30a27866e2c", size = 3910543, upload-time = "2025-12-02T21:08:48.202Z" }, + { url = "https://files.pythonhosted.org/packages/dc/89/7ad39e369706beda88827031504d9bb5fed58bf6fe50ec7045bd6750736b/psycopg_binary-3.3.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3986f783ff656a0392b81b7ac1e0f88a276a38276a5c93c0b89d4862e309d618", size = 4220070, upload-time = "2025-12-02T21:08:52.752Z" }, + { url = "https://files.pythonhosted.org/packages/ad/3a/703c155ab9fb64c874921116fd740c93494e6bd599b1bcd9e4987f5dcfb4/psycopg_binary-3.3.1-cp313-cp313-win_amd64.whl", hash = "sha256:63e7c689a4249a1303da35df0b813e7cb3b9e2e5eae492a47482ee1a41dc66b2", size = 3540907, upload-time = "2025-12-02T21:08:56.898Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pycparser" +version = "2.23" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/cf/d2d3b9f5699fb1e4615c8e32ff220203e43b248e1dfcc6736ad9057731ca/pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2", size = 173734, upload-time = "2025-09-09T13:23:47.91Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/e3/59cd50310fc9b59512193629e1984c1f95e5c8ae6e5d8c69532ccc65a7fe/pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934", size = 118140, upload-time = "2025-09-09T13:23:46.651Z" }, +] + +[[package]] +name = "pyfakefs" +version = "5.10.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/1c/4b9489847535a41e074d108bfb86119ab463aa3012f4cb8f6b7f9154e00a/pyfakefs-5.10.2.tar.gz", hash = "sha256:8ae0e5421e08de4e433853a4609a06a1835f4bc2a3ce13b54f36713a897474ba", size = 231379, upload-time = "2025-11-04T20:19:04.446Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/65/3a15447a8630a6bb79cf1ecd9e323a72b28830cb9f367494bedcd045059d/pyfakefs-5.10.2-py3-none-any.whl", hash = "sha256:6ff0e84653a71efc6a73f9ee839c3141e3a7cdf4e1fb97666f82ac5b24308d64", size = 246305, upload-time = "2025-11-04T20:19:02.583Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[[package]] +name = "pylint" +version = "3.3.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "astroid" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "dill" }, + { name = "isort" }, + { name = "mccabe" }, + { name = "platformdirs" }, + { name = "tomlkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/04/9d/81c84a312d1fa8133b0db0c76148542a98349298a01747ab122f9314b04e/pylint-3.3.9.tar.gz", hash = "sha256:d312737d7b25ccf6b01cc4ac629b5dcd14a0fcf3ec392735ac70f137a9d5f83a", size = 1525946, upload-time = "2025-10-05T18:41:43.786Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1a/a7/69460c4a6af7575449e615144aa2205b89408dc2969b87bc3df2f262ad0b/pylint-3.3.9-py3-none-any.whl", hash = "sha256:01f9b0462c7730f94786c283f3e52a1fbdf0494bbe0971a78d7277ef46a751e7", size = 523465, upload-time = "2025-10-05T18:41:41.766Z" }, +] + +[[package]] +name = "pylint-django" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pylint" }, + { name = "pylint-plugin-utils" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/d3/42f88e7549c6d69d9642e7f2de7a1a4a3d45fd352a8ca049c554a3feaba0/pylint-django-2.6.1.tar.gz", hash = "sha256:19e8c85a8573a04e3de7be2ba91e9a7c818ebf05e1b617be2bbae67a906b725f", size = 31970, upload-time = "2024-10-10T14:46:37.931Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/82/88b58feecce482e76e4ec4a45e44ed28075fddd82530d071d89466e83529/pylint_django-2.6.1-py3-none-any.whl", hash = "sha256:359f68fe8c810ee6bc8e1ab4c83c19b15a43b234a24b08978f47a23462b5ce28", size = 42858, upload-time = "2024-10-10T14:46:36.236Z" }, +] + +[[package]] +name = "pylint-plugin-utils" +version = "0.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pylint" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/73/85/24eaf5d0d078fc8799ae6d89faf326d6e4d27d862fc9a710a52ab07b7bb5/pylint_plugin_utils-0.9.0.tar.gz", hash = "sha256:5468d763878a18d5cc4db46eaffdda14313b043c962a263a7d78151b90132055", size = 10474, upload-time = "2025-06-24T07:14:00.534Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5e/c9/a3b871b0b590c49e38884af6dab58ab9711053bd5c39b8899b72e367b9f6/pylint_plugin_utils-0.9.0-py3-none-any.whl", hash = "sha256:16e9b84e5326ba893a319a0323fcc8b4bcc9c71fc654fcabba0605596c673818", size = 11129, upload-time = "2025-06-24T07:13:58.993Z" }, +] + +[[package]] +name = "pytest" +version = "9.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/07/56/f013048ac4bc4c1d9be45afd4ab209ea62822fb1598f40687e6bf45dcea4/pytest-9.0.1.tar.gz", hash = "sha256:3e9c069ea73583e255c3b21cf46b8d3c56f6e3a1a8f6da94ccb0fcf57b9d73c8", size = 1564125, upload-time = "2025-11-12T13:05:09.333Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/8b/6300fb80f858cda1c51ffa17075df5d846757081d11ab4aa35cef9e6258b/pytest-9.0.1-py3-none-any.whl", hash = "sha256:67be0030d194df2dfa7b556f2e56fb3c3315bd5c8822c6951162b92b32ce7dad", size = 373668, upload-time = "2025-11-12T13:05:07.379Z" }, +] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/f7/c933acc76f5208b3b00089573cf6a2bc26dc80a8aece8f52bb7d6b1855ca/pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1", size = 54328, upload-time = "2025-09-09T10:57:02.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ee/49/1377b49de7d0c1ce41292161ea0f721913fa8722c19fb9c1e3aa0367eecb/pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861", size = 22424, upload-time = "2025-09-09T10:57:00.695Z" }, +] + +[[package]] +name = "pytest-django" +version = "4.11.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b1/fb/55d580352db26eb3d59ad50c64321ddfe228d3d8ac107db05387a2fadf3a/pytest_django-4.11.1.tar.gz", hash = "sha256:a949141a1ee103cb0e7a20f1451d355f83f5e4a5d07bdd4dcfdd1fd0ff227991", size = 86202, upload-time = "2025-04-03T18:56:09.338Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/ac/bd0608d229ec808e51a21044f3f2f27b9a37e7a0ebaca7247882e67876af/pytest_django-4.11.1-py3-none-any.whl", hash = "sha256:1b63773f648aa3d8541000c26929c1ea63934be1cfa674c76436966d73fe6a10", size = 25281, upload-time = "2025-04-03T18:56:07.678Z" }, +] + +[[package]] +name = "pytest-icdiff" +version = "0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "icdiff" }, + { name = "pprintpp" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5a/0c/66e1e2590e98f4428e374a3b6448dc086a908d15b1e24b914539d13b7ac4/pytest-icdiff-0.9.tar.gz", hash = "sha256:13aede616202e57fcc882568b64589002ef85438046f012ac30a8d959dac8b75", size = 7110, upload-time = "2023-12-05T11:18:30.192Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e2/e1/cafe1edf7a30be6fa1bbbf43f7af12b34682eadcf19eb6e9f7352062c422/pytest_icdiff-0.9-py3-none-any.whl", hash = "sha256:efee0da3bd1b24ef2d923751c5c547fbb8df0a46795553fba08ef57c3ca03d82", size = 4994, upload-time = "2023-12-05T11:18:28.572Z" }, +] + +[[package]] +name = "pytest-xdist" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "execnet" }, + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/b4/439b179d1ff526791eb921115fca8e44e596a13efeda518b9d845a619450/pytest_xdist-3.8.0.tar.gz", hash = "sha256:7e578125ec9bc6050861aa93f2d59f1d8d085595d6551c2c90b6f4fad8d3a9f1", size = 88069, upload-time = "2025-07-01T13:30:59.346Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ca/31/d4e37e9e550c2b92a9cbc2e4d0b7420a27224968580b5a447f420847c975/pytest_xdist-3.8.0-py3-none-any.whl", hash = "sha256:202ca578cfeb7370784a8c33d6d05bc6e13b4f25b5053c30a152269fd10f0b88", size = 46396, upload-time = "2025-07-01T13:30:56.632Z" }, +] + +[[package]] +name = "python-crontab" +version = "3.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/99/7f/c54fb7e70b59844526aa4ae321e927a167678660ab51dda979955eafb89a/python_crontab-3.3.0.tar.gz", hash = "sha256:007c8aee68dddf3e04ec4dce0fac124b93bd68be7470fc95d2a9617a15de291b", size = 57626, upload-time = "2025-07-13T20:05:35.535Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/42/bb4afa5b088f64092036221843fc989b7db9d9d302494c1f8b024ee78a46/python_crontab-3.3.0-py3-none-any.whl", hash = "sha256:739a778b1a771379b75654e53fd4df58e5c63a9279a63b5dfe44c0fcc3ee7884", size = 27533, upload-time = "2025-07-13T20:05:34.266Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz", hash = "sha256:d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f", size = 130960, upload-time = "2025-09-25T21:33:16.546Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/11/0fd08f8192109f7169db964b5707a2f1e8b745d4e239b784a5a1dd80d1db/pyyaml-6.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8da9669d359f02c0b91ccc01cac4a67f16afec0dac22c2ad09f46bee0697eba8", size = 181669, upload-time = "2025-09-25T21:32:23.673Z" }, + { url = "https://files.pythonhosted.org/packages/b1/16/95309993f1d3748cd644e02e38b75d50cbc0d9561d21f390a76242ce073f/pyyaml-6.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:2283a07e2c21a2aa78d9c4442724ec1eb15f5e42a723b99cb3d822d48f5f7ad1", size = 173252, upload-time = "2025-09-25T21:32:25.149Z" }, + { url = "https://files.pythonhosted.org/packages/50/31/b20f376d3f810b9b2371e72ef5adb33879b25edb7a6d072cb7ca0c486398/pyyaml-6.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ee2922902c45ae8ccada2c5b501ab86c36525b883eff4255313a253a3160861c", size = 767081, upload-time = "2025-09-25T21:32:26.575Z" }, + { url = "https://files.pythonhosted.org/packages/49/1e/a55ca81e949270d5d4432fbbd19dfea5321eda7c41a849d443dc92fd1ff7/pyyaml-6.0.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a33284e20b78bd4a18c8c2282d549d10bc8408a2a7ff57653c0cf0b9be0afce5", size = 841159, upload-time = "2025-09-25T21:32:27.727Z" }, + { url = "https://files.pythonhosted.org/packages/74/27/e5b8f34d02d9995b80abcef563ea1f8b56d20134d8f4e5e81733b1feceb2/pyyaml-6.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f29edc409a6392443abf94b9cf89ce99889a1dd5376d94316ae5145dfedd5d6", size = 801626, upload-time = "2025-09-25T21:32:28.878Z" }, + { url = "https://files.pythonhosted.org/packages/f9/11/ba845c23988798f40e52ba45f34849aa8a1f2d4af4b798588010792ebad6/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:f7057c9a337546edc7973c0d3ba84ddcdf0daa14533c2065749c9075001090e6", size = 753613, upload-time = "2025-09-25T21:32:30.178Z" }, + { url = "https://files.pythonhosted.org/packages/3d/e0/7966e1a7bfc0a45bf0a7fb6b98ea03fc9b8d84fa7f2229e9659680b69ee3/pyyaml-6.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:eda16858a3cab07b80edaf74336ece1f986ba330fdb8ee0d6c0d68fe82bc96be", size = 794115, upload-time = "2025-09-25T21:32:31.353Z" }, + { url = "https://files.pythonhosted.org/packages/de/94/980b50a6531b3019e45ddeada0626d45fa85cbe22300844a7983285bed3b/pyyaml-6.0.3-cp313-cp313-win32.whl", hash = "sha256:d0eae10f8159e8fdad514efdc92d74fd8d682c933a6dd088030f3834bc8e6b26", size = 137427, upload-time = "2025-09-25T21:32:32.58Z" }, + { url = "https://files.pythonhosted.org/packages/97/c9/39d5b874e8b28845e4ec2202b5da735d0199dbe5b8fb85f91398814a9a46/pyyaml-6.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:79005a0d97d5ddabfeeea4cf676af11e647e41d81c9a7722a193022accdb6b7c", size = 154090, upload-time = "2025-09-25T21:32:33.659Z" }, + { url = "https://files.pythonhosted.org/packages/73/e8/2bdf3ca2090f68bb3d75b44da7bbc71843b19c9f2b9cb9b0f4ab7a5a4329/pyyaml-6.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:5498cd1645aa724a7c71c8f378eb29ebe23da2fc0d7a08071d89469bf1d2defb", size = 140246, upload-time = "2025-09-25T21:32:34.663Z" }, +] + +[[package]] +name = "qh3" +version = "1.5.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/e4/6898c3c3c0d3a5ba62729599edf145acde478cd9d088e5dfd85e3866a610/qh3-1.5.6.tar.gz", hash = "sha256:5c7fb081a07512dcace9a49179a40dc00ad1f77b2779ee4bb7ca176f96552f66", size = 269753, upload-time = "2025-11-09T05:52:49.787Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/7c/11b4240c7e973c2ed2e7d06252faa4f50b346d3a7a83952c5c8a8d53e26c/qh3-1.5.6-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:6febfda5cc9decfb6cf0df122b87370b3569b36a9035740756c9d75399f59c9c", size = 4476698, upload-time = "2025-11-09T05:34:38.728Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8d/0ab2d3013cc8c03a68f36282ba1bf31a65cafa952f37bce4b44c2de853a2/qh3-1.5.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57a5c78fce81288e6c28a45db4e8320db2329e728ebdde9cd1787bbd57cec55f", size = 2174544, upload-time = "2025-11-09T05:34:41.592Z" }, + { url = "https://files.pythonhosted.org/packages/6a/8c/70776a12d56cb4275132e707a3ad4e8712f8044f72a948a848eecf29b9ca/qh3-1.5.6-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ec1d69a3671066a4c06f05d00ed966540f4c7a73b062da15d19123a6aa723c3f", size = 1897113, upload-time = "2025-11-09T05:34:43.46Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fd/5d7333743de27ac7cae46c3afa5da75f3dc3892e9041170d25d636b8132c/qh3-1.5.6-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e770b0ed58659a8aec1fe2a323eda188297b941387ef8a308805149ff48700ea", size = 2042349, upload-time = "2025-11-09T05:34:45.354Z" }, + { url = "https://files.pythonhosted.org/packages/89/32/026cb88cb36cda17a8ba8570f4a8eb3fdfed49ffdb28f3d44699f6ebb4a5/qh3-1.5.6-cp313-cp313t-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2ac1dddbcd11d1afc785002a2d0f906bd24ff0b9a18d9f544327bd07a9da877d", size = 2025049, upload-time = "2025-11-09T05:34:47.319Z" }, + { url = "https://files.pythonhosted.org/packages/58/ed/f92681010217ba6712c9b8aeeff0a40a8955a70e11d5ae76fe2daf7075ba/qh3-1.5.6-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ca0751772272e9d65201ca7f84fcf82a00d8599e2adfe3c62aa0249d3bb5602", size = 2068510, upload-time = "2025-11-09T05:34:49.343Z" }, + { url = "https://files.pythonhosted.org/packages/11/cc/6412c82f37da6bd6fb1218aba2e86d0638a7a2573c057bf24137d64b9857/qh3-1.5.6-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08b87bd76d06d225dca95882cac916faf2b178faca3c2d9d1da552174c19be4f", size = 2091524, upload-time = "2025-11-09T05:34:51.203Z" }, + { url = "https://files.pythonhosted.org/packages/17/b3/0f4af1a7e1bed99dedcd24203d504ee356671c056cecf6fd8f7989bf28cf/qh3-1.5.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd4f631036c4b8e30e033009afababdd04591b25da51a0308d8341b4c27d0f06", size = 2372423, upload-time = "2025-11-09T05:34:53.136Z" }, + { url = "https://files.pythonhosted.org/packages/2a/59/8b3825a34510f8a8e2bd501ffa73ddd5434d092f4f2d8ec9b4834e6c7f1a/qh3-1.5.6-cp313-cp313t-manylinux_2_39_riscv64.whl", hash = "sha256:e40abdfbaf5a8d02b638c3d3d818f6380f3ba5c75b071493ca402c63d361cf55", size = 2033771, upload-time = "2025-11-09T05:34:55.056Z" }, + { url = "https://files.pythonhosted.org/packages/de/af/4a0d3026b3f48ca6cf60b63741e6b62e1435dc489aa068bd26116da44f74/qh3-1.5.6-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:03e8fe16f62a252f05a51f6bfe3dc8e6563cd18d6328fc194da1647632f89f8d", size = 2369697, upload-time = "2025-11-09T05:34:56.956Z" }, + { url = "https://files.pythonhosted.org/packages/6c/db/a18b99c01b4d4ef7d4508d034b702a9cc6788e9099f231090722bb252344/qh3-1.5.6-cp313-cp313t-musllinux_1_1_armv7l.whl", hash = "sha256:6b0994e89783246cf448550817c86380cbde1f65fc8835a489c0361f5ee68da7", size = 2135581, upload-time = "2025-11-09T05:34:58.938Z" }, + { url = "https://files.pythonhosted.org/packages/8b/da/7fe9372887a07381f203236aa1e38dbb58bbed29f463f7e2206958d1c98e/qh3-1.5.6-cp313-cp313t-musllinux_1_1_i686.whl", hash = "sha256:f5bae59549f11e6404451274ae7ca4a80558a01175596d032fd88066f89d103b", size = 2164165, upload-time = "2025-11-09T05:35:00.931Z" }, + { url = "https://files.pythonhosted.org/packages/00/b9/eeca4cb0194f78b2fab49ae40bac881767ab283115fe10579a42d2292904/qh3-1.5.6-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:6e4060949f4b3b4bb3d3aedf0a274d6c40c35f3d856c0345b1ce4cb49847ca4b", size = 2544894, upload-time = "2025-11-09T05:35:02.476Z" }, + { url = "https://files.pythonhosted.org/packages/92/27/5d3409a55b9428c599b9068b2ec8ad2999c338d4c8662db18427934f01c3/qh3-1.5.6-cp313-cp313t-win32.whl", hash = "sha256:91ac8000102b88636854e9b096b5684e06b9c231707e4c9e9440fbe2a493042e", size = 1735030, upload-time = "2025-11-09T05:35:04.424Z" }, + { url = "https://files.pythonhosted.org/packages/00/2d/af22246a43087c0f654f48b3fb648dcfc53eb5eb74242bb1047598be344b/qh3-1.5.6-cp313-cp313t-win_amd64.whl", hash = "sha256:e9dcc8c2ca5b308c42d0e24bd9972e6394d782bac2939901552494e16ac39245", size = 1986491, upload-time = "2025-11-09T05:35:06.863Z" }, + { url = "https://files.pythonhosted.org/packages/9b/06/bab6ea59c2f5c1c8c061f1c24840043585f92c31e6811c3a7005a3598df5/qh3-1.5.6-cp313-cp313t-win_arm64.whl", hash = "sha256:2e66257ee6b1acd449ed9e0290fa500800a25720a3bd12d5d37bd6e815d05ee1", size = 1816042, upload-time = "2025-11-09T05:50:13.263Z" }, + { url = "https://files.pythonhosted.org/packages/4c/5c/6c49f8d12da29eedd048039c1b3c33ffd4db8c2ed4c82afe91d31f00afc4/qh3-1.5.6-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:28b03fe0c7d8989c429426e0744d4eea1ffd976a8fe4e63a0164c2b56e8d4976", size = 4491221, upload-time = "2025-11-09T05:50:40.821Z" }, + { url = "https://files.pythonhosted.org/packages/7a/bc/5942a9189f1452744eeacff89ade2d58a312f11c5a1dd57c183bbd86c9c7/qh3-1.5.6-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1842aa5440b8c94a392202aa19e3593a597fe1e808950de00602bf7d46f6f8a3", size = 2177685, upload-time = "2025-11-09T05:50:42.182Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ab/1c7715bd18db347963bcda00768f387a3935c88d92ccd3292cbcd46edb26/qh3-1.5.6-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9804cf7329364c94075232ff0edaad86bc696c18a4ee6b46b4320b8716737b1a", size = 1898292, upload-time = "2025-11-09T05:50:44.223Z" }, + { url = "https://files.pythonhosted.org/packages/c1/93/1f8976a62f280fcd8520bfd627235a6241b30d380084ffa74bfd89530260/qh3-1.5.6-cp37-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b64fd616d20028ed06450cf0a6743b739bc46500990003f9dfac7080b83466b", size = 2043209, upload-time = "2025-11-09T05:50:45.742Z" }, + { url = "https://files.pythonhosted.org/packages/00/70/f350c4a61bbe1c3cfb719efef90ee1c609a8986637c1623abbdac00f837c/qh3-1.5.6-cp37-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:690bbf3075aa51999f61932da4ccee4f70645059a700da7025709867a39a0868", size = 2027699, upload-time = "2025-11-09T05:50:47.097Z" }, + { url = "https://files.pythonhosted.org/packages/73/27/cea3edc242d65768dbccae3859a260b187e23f98dddf75cad5875cff9beb/qh3-1.5.6-cp37-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6987bedcdd8d5d156e21723c4d21575da4cdae31f8eb6b04b64796b68a43ad41", size = 2075827, upload-time = "2025-11-09T05:50:48.684Z" }, + { url = "https://files.pythonhosted.org/packages/8a/3e/8a90dd20618f408983aaff08e0ca9b343cc2b1f29d696827493be14f5c2e/qh3-1.5.6-cp37-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:11bcca3ffd03e6914f626bbe0f4392b89190ff4fd33a5bdc26b5b1fddae9ab9e", size = 2098224, upload-time = "2025-11-09T05:50:50.159Z" }, + { url = "https://files.pythonhosted.org/packages/01/b8/41e849d7164b6ba1a61f66c6687008d750ee8b605a194a444197a7151d85/qh3-1.5.6-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:692722cd545bcc6c8d6de3ac58ea875f7f43e2cb014be64e267511e8d16bafcd", size = 2375936, upload-time = "2025-11-09T05:50:52.485Z" }, + { url = "https://files.pythonhosted.org/packages/1a/ab/5a9a63901b3bb8a622db523ca785ac14b0e703d55f7796db860dfd671d0c/qh3-1.5.6-cp37-abi3-manylinux_2_39_riscv64.whl", hash = "sha256:91b523f9a7c4d083a831d89663d8aaf45128ad325f3049de4f48678d5e45b211", size = 2039073, upload-time = "2025-11-09T05:50:54.142Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d7/be9a2ef6da5da7e6be98a855cc133559bc88da7b5bb21d0c4dde5d71a0c6/qh3-1.5.6-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:2f6dd167e6458566825b371a27731092b15a0a527b32e831d21cd4ecb190566a", size = 2370983, upload-time = "2025-11-09T05:50:55.652Z" }, + { url = "https://files.pythonhosted.org/packages/af/e3/ca1eccf6744b77aa744012c4c15350ee7f4e39818786c81ad4ee4a9f7564/qh3-1.5.6-cp37-abi3-musllinux_1_1_armv7l.whl", hash = "sha256:414ad77504a78c521d71ddb8a6d0a1230528ab64184a098424d2ec45c1b570ec", size = 2136965, upload-time = "2025-11-09T05:50:57.181Z" }, + { url = "https://files.pythonhosted.org/packages/08/67/4caf81f598ce0a4a5dc029492ea9cf2c48c1c98921be8c42d8005768b6e2/qh3-1.5.6-cp37-abi3-musllinux_1_1_i686.whl", hash = "sha256:ef9bfaab22114f8fd36094246f774d8fc5bbc74421aebb742f392feaab04ecb3", size = 2166958, upload-time = "2025-11-09T05:50:58.633Z" }, + { url = "https://files.pythonhosted.org/packages/22/51/196722ef0b0016968e2439720f4dce63ba7f641663cb61ad67bf089c6096/qh3-1.5.6-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:20686c57eb45087e644cd749cdd372e082af4845249eb946ffab9c4c3fb5b364", size = 2546184, upload-time = "2025-11-09T05:51:00.005Z" }, + { url = "https://files.pythonhosted.org/packages/74/e2/20c8c3e21b5465ed9373255216ad4657c58119eff45b99a5e4138c9caf68/qh3-1.5.6-cp37-abi3-win32.whl", hash = "sha256:deefa7d329df97fe4df7b5f2ce806378bb72c1b7b0329439dd8052e916679428", size = 1738876, upload-time = "2025-11-09T05:51:01.701Z" }, + { url = "https://files.pythonhosted.org/packages/31/b4/b67841c3442929caad6c65e937eefe5df7828427fad249e290d13b2df01a/qh3-1.5.6-cp37-abi3-win_amd64.whl", hash = "sha256:84992d0810cc53b33f122cd411be87d36c942e104aa6252d10ee03e1a6d6fb4d", size = 1991436, upload-time = "2025-11-09T05:51:03.438Z" }, +] + +[[package]] +name = "recurring-ical-events" +version = "3.8.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "icalendar" }, + { name = "python-dateutil" }, + { name = "tzdata" }, + { name = "x-wr-timezone" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/90/05dfcc02ecf58bd170305c88db9e3e3933aa73a1f8abac2b326c7fdc1a98/recurring_ical_events-3.8.0.tar.gz", hash = "sha256:3e8c7c35d9bd8956a7ab91afad51477c60d972e1236d3fd1b55087a66bce7d04", size = 602665, upload-time = "2025-06-10T13:23:50.662Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/36/25/88a4218cccae06ce6b15e41d2f263dd4a73e8e8cbe41537cd7784a17479b/recurring_ical_events-3.8.0-py3-none-any.whl", hash = "sha256:cf958eb17c92d4dca5c621e44c2b3fffd4ba700dca0db66287c5dc11438f63ba", size = 238228, upload-time = "2025-06-10T13:23:49.048Z" }, +] + +[[package]] +name = "redis" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyjwt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/cf/128b1b6d7086200c9f387bd4be9b2572a30b90745ef078bd8b235042dc9f/redis-5.3.1.tar.gz", hash = "sha256:ca49577a531ea64039b5a36db3d6cd1a0c7a60c34124d46924a45b956e8cf14c", size = 4626200, upload-time = "2025-07-25T08:06:27.778Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl", hash = "sha256:dc1909bd24669cc31b5f67a039700b16ec30571096c5f1f0d9d2324bff31af97", size = 272833, upload-time = "2025-07-25T08:06:26.317Z" }, +] + +[[package]] +name = "referencing" +version = "0.37.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/22/f5/df4e9027acead3ecc63e50fe1e36aca1523e1719559c499951bb4b53188f/referencing-0.37.0.tar.gz", hash = "sha256:44aefc3142c5b842538163acb373e24cce6632bd54bdb01b21ad5863489f50d8", size = 78036, upload-time = "2025-10-13T15:30:48.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, +] + +[[package]] +name = "responses" +version = "0.25.8" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, + { name = "requests" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0e/95/89c054ad70bfef6da605338b009b2e283485835351a9935c7bfbfaca7ffc/responses-0.25.8.tar.gz", hash = "sha256:9374d047a575c8f781b94454db5cab590b6029505f488d12899ddb10a4af1cf4", size = 79320, upload-time = "2025-08-08T19:01:46.709Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1c/4c/cc276ce57e572c102d9542d383b2cfd551276581dc60004cb94fe8774c11/responses-0.25.8-py3-none-any.whl", hash = "sha256:0c710af92def29c8352ceadff0c3fe340ace27cf5af1bbe46fb71275bcd2831c", size = 34769, upload-time = "2025-08-08T19:01:45.018Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.30.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/af/3f2f423103f1113b36230496629986e0ef7e199d2aa8392452b484b38ced/rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84", size = 69469, upload-time = "2025-11-30T20:24:38.837Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/dc/d61221eb88ff410de3c49143407f6f3147acf2538c86f2ab7ce65ae7d5f9/rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2", size = 374887, upload-time = "2025-11-30T20:22:41.812Z" }, + { url = "https://files.pythonhosted.org/packages/fd/32/55fb50ae104061dbc564ef15cc43c013dc4a9f4527a1f4d99baddf56fe5f/rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8", size = 358904, upload-time = "2025-11-30T20:22:43.479Z" }, + { url = "https://files.pythonhosted.org/packages/58/70/faed8186300e3b9bdd138d0273109784eea2396c68458ed580f885dfe7ad/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4", size = 389945, upload-time = "2025-11-30T20:22:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/bd/a8/073cac3ed2c6387df38f71296d002ab43496a96b92c823e76f46b8af0543/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136", size = 407783, upload-time = "2025-11-30T20:22:46.103Z" }, + { url = "https://files.pythonhosted.org/packages/77/57/5999eb8c58671f1c11eba084115e77a8899d6e694d2a18f69f0ba471ec8b/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7", size = 515021, upload-time = "2025-11-30T20:22:47.458Z" }, + { url = "https://files.pythonhosted.org/packages/e0/af/5ab4833eadc36c0a8ed2bc5c0de0493c04f6c06de223170bd0798ff98ced/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2", size = 414589, upload-time = "2025-11-30T20:22:48.872Z" }, + { url = "https://files.pythonhosted.org/packages/b7/de/f7192e12b21b9e9a68a6d0f249b4af3fdcdff8418be0767a627564afa1f1/rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6", size = 394025, upload-time = "2025-11-30T20:22:50.196Z" }, + { url = "https://files.pythonhosted.org/packages/91/c4/fc70cd0249496493500e7cc2de87504f5aa6509de1e88623431fec76d4b6/rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e", size = 408895, upload-time = "2025-11-30T20:22:51.87Z" }, + { url = "https://files.pythonhosted.org/packages/58/95/d9275b05ab96556fefff73a385813eb66032e4c99f411d0795372d9abcea/rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d", size = 422799, upload-time = "2025-11-30T20:22:53.341Z" }, + { url = "https://files.pythonhosted.org/packages/06/c1/3088fc04b6624eb12a57eb814f0d4997a44b0d208d6cace713033ff1a6ba/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7", size = 572731, upload-time = "2025-11-30T20:22:54.778Z" }, + { url = "https://files.pythonhosted.org/packages/d8/42/c612a833183b39774e8ac8fecae81263a68b9583ee343db33ab571a7ce55/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31", size = 599027, upload-time = "2025-11-30T20:22:56.212Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/525a50f45b01d70005403ae0e25f43c0384369ad24ffe46e8d9068b50086/rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95", size = 563020, upload-time = "2025-11-30T20:22:58.2Z" }, + { url = "https://files.pythonhosted.org/packages/0b/5d/47c4655e9bcd5ca907148535c10e7d489044243cc9941c16ed7cd53be91d/rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d", size = 223139, upload-time = "2025-11-30T20:23:00.209Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e1/485132437d20aa4d3e1d8b3fb5a5e65aa8139f1e097080c2a8443201742c/rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15", size = 240224, upload-time = "2025-11-30T20:23:02.008Z" }, + { url = "https://files.pythonhosted.org/packages/24/95/ffd128ed1146a153d928617b0ef673960130be0009c77d8fbf0abe306713/rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1", size = 230645, upload-time = "2025-11-30T20:23:03.43Z" }, + { url = "https://files.pythonhosted.org/packages/ff/1b/b10de890a0def2a319a2626334a7f0ae388215eb60914dbac8a3bae54435/rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a", size = 364443, upload-time = "2025-11-30T20:23:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/0d/bf/27e39f5971dc4f305a4fb9c672ca06f290f7c4e261c568f3dea16a410d47/rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e", size = 353375, upload-time = "2025-11-30T20:23:06.342Z" }, + { url = "https://files.pythonhosted.org/packages/40/58/442ada3bba6e8e6615fc00483135c14a7538d2ffac30e2d933ccf6852232/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000", size = 383850, upload-time = "2025-11-30T20:23:07.825Z" }, + { url = "https://files.pythonhosted.org/packages/14/14/f59b0127409a33c6ef6f5c1ebd5ad8e32d7861c9c7adfa9a624fc3889f6c/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db", size = 392812, upload-time = "2025-11-30T20:23:09.228Z" }, + { url = "https://files.pythonhosted.org/packages/b3/66/e0be3e162ac299b3a22527e8913767d869e6cc75c46bd844aa43fb81ab62/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2", size = 517841, upload-time = "2025-11-30T20:23:11.186Z" }, + { url = "https://files.pythonhosted.org/packages/3d/55/fa3b9cf31d0c963ecf1ba777f7cf4b2a2c976795ac430d24a1f43d25a6ba/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa", size = 408149, upload-time = "2025-11-30T20:23:12.864Z" }, + { url = "https://files.pythonhosted.org/packages/60/ca/780cf3b1a32b18c0f05c441958d3758f02544f1d613abf9488cd78876378/rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083", size = 383843, upload-time = "2025-11-30T20:23:14.638Z" }, + { url = "https://files.pythonhosted.org/packages/82/86/d5f2e04f2aa6247c613da0c1dd87fcd08fa17107e858193566048a1e2f0a/rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9", size = 396507, upload-time = "2025-11-30T20:23:16.105Z" }, + { url = "https://files.pythonhosted.org/packages/4b/9a/453255d2f769fe44e07ea9785c8347edaf867f7026872e76c1ad9f7bed92/rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0", size = 414949, upload-time = "2025-11-30T20:23:17.539Z" }, + { url = "https://files.pythonhosted.org/packages/a3/31/622a86cdc0c45d6df0e9ccb6becdba5074735e7033c20e401a6d9d0e2ca0/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94", size = 565790, upload-time = "2025-11-30T20:23:19.029Z" }, + { url = "https://files.pythonhosted.org/packages/1c/5d/15bbf0fb4a3f58a3b1c67855ec1efcc4ceaef4e86644665fff03e1b66d8d/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08", size = 590217, upload-time = "2025-11-30T20:23:20.885Z" }, + { url = "https://files.pythonhosted.org/packages/6d/61/21b8c41f68e60c8cc3b2e25644f0e3681926020f11d06ab0b78e3c6bbff1/rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27", size = 555806, upload-time = "2025-11-30T20:23:22.488Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/7e067bb06c31de48de3eb200f9fc7c58982a4d3db44b07e73963e10d3be9/rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6", size = 211341, upload-time = "2025-11-30T20:23:24.449Z" }, + { url = "https://files.pythonhosted.org/packages/0a/4d/222ef0b46443cf4cf46764d9c630f3fe4abaa7245be9417e56e9f52b8f65/rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d", size = 225768, upload-time = "2025-11-30T20:23:25.908Z" }, +] + +[[package]] +name = "ruff" +version = "0.14.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/5b/dd7406afa6c95e3d8fa9d652b6d6dd17dd4a6bf63cb477014e8ccd3dcd46/ruff-0.14.7.tar.gz", hash = "sha256:3417deb75d23bd14a722b57b0a1435561db65f0ad97435b4cf9f85ffcef34ae5", size = 5727324, upload-time = "2025-11-28T20:55:10.525Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/b1/7ea5647aaf90106f6d102230e5df874613da43d1089864da1553b899ba5e/ruff-0.14.7-py3-none-linux_armv6l.whl", hash = "sha256:b9d5cb5a176c7236892ad7224bc1e63902e4842c460a0b5210701b13e3de4fca", size = 13414475, upload-time = "2025-11-28T20:54:54.569Z" }, + { url = "https://files.pythonhosted.org/packages/af/19/fddb4cd532299db9cdaf0efdc20f5c573ce9952a11cb532d3b859d6d9871/ruff-0.14.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:3f64fe375aefaf36ca7d7250292141e39b4cea8250427482ae779a2aa5d90015", size = 13634613, upload-time = "2025-11-28T20:55:17.54Z" }, + { url = "https://files.pythonhosted.org/packages/40/2b/469a66e821d4f3de0440676ed3e04b8e2a1dc7575cf6fa3ba6d55e3c8557/ruff-0.14.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:93e83bd3a9e1a3bda64cb771c0d47cda0e0d148165013ae2d3554d718632d554", size = 12765458, upload-time = "2025-11-28T20:55:26.128Z" }, + { url = "https://files.pythonhosted.org/packages/f1/05/0b001f734fe550bcfde4ce845948ac620ff908ab7241a39a1b39bb3c5f49/ruff-0.14.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3838948e3facc59a6070795de2ae16e5786861850f78d5914a03f12659e88f94", size = 13236412, upload-time = "2025-11-28T20:55:28.602Z" }, + { url = "https://files.pythonhosted.org/packages/11/36/8ed15d243f011b4e5da75cd56d6131c6766f55334d14ba31cce5461f28aa/ruff-0.14.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:24c8487194d38b6d71cd0fd17a5b6715cda29f59baca1defe1e3a03240f851d1", size = 13182949, upload-time = "2025-11-28T20:55:33.265Z" }, + { url = "https://files.pythonhosted.org/packages/3b/cf/fcb0b5a195455729834f2a6eadfe2e4519d8ca08c74f6d2b564a4f18f553/ruff-0.14.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:79c73db6833f058a4be8ffe4a0913b6d4ad41f6324745179bd2aa09275b01d0b", size = 13816470, upload-time = "2025-11-28T20:55:08.203Z" }, + { url = "https://files.pythonhosted.org/packages/7f/5d/34a4748577ff7a5ed2f2471456740f02e86d1568a18c9faccfc73bd9ca3f/ruff-0.14.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:12eb7014fccff10fc62d15c79d8a6be4d0c2d60fe3f8e4d169a0d2def75f5dad", size = 15289621, upload-time = "2025-11-28T20:55:30.837Z" }, + { url = "https://files.pythonhosted.org/packages/53/53/0a9385f047a858ba133d96f3f8e3c9c66a31cc7c4b445368ef88ebeac209/ruff-0.14.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c623bbdc902de7ff715a93fa3bb377a4e42dd696937bf95669118773dbf0c50", size = 14975817, upload-time = "2025-11-28T20:55:24.107Z" }, + { url = "https://files.pythonhosted.org/packages/a8/d7/2f1c32af54c3b46e7fadbf8006d8b9bcfbea535c316b0bd8813d6fb25e5d/ruff-0.14.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f53accc02ed2d200fa621593cdb3c1ae06aa9b2c3cae70bc96f72f0000ae97a9", size = 14284549, upload-time = "2025-11-28T20:55:06.08Z" }, + { url = "https://files.pythonhosted.org/packages/92/05/434ddd86becd64629c25fb6b4ce7637dd52a45cc4a4415a3008fe61c27b9/ruff-0.14.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:281f0e61a23fcdcffca210591f0f53aafaa15f9025b5b3f9706879aaa8683bc4", size = 14071389, upload-time = "2025-11-28T20:55:35.617Z" }, + { url = "https://files.pythonhosted.org/packages/ff/50/fdf89d4d80f7f9d4f420d26089a79b3bb1538fe44586b148451bc2ba8d9c/ruff-0.14.7-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:dbbaa5e14148965b91cb090236931182ee522a5fac9bc5575bafc5c07b9f9682", size = 14202679, upload-time = "2025-11-28T20:55:01.472Z" }, + { url = "https://files.pythonhosted.org/packages/77/54/87b34988984555425ce967f08a36df0ebd339bb5d9d0e92a47e41151eafc/ruff-0.14.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1464b6e54880c0fe2f2d6eaefb6db15373331414eddf89d6b903767ae2458143", size = 13147677, upload-time = "2025-11-28T20:55:19.933Z" }, + { url = "https://files.pythonhosted.org/packages/67/29/f55e4d44edfe053918a16a3299e758e1c18eef216b7a7092550d7a9ec51c/ruff-0.14.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f217ed871e4621ea6128460df57b19ce0580606c23aeab50f5de425d05226784", size = 13151392, upload-time = "2025-11-28T20:55:21.967Z" }, + { url = "https://files.pythonhosted.org/packages/36/69/47aae6dbd4f1d9b4f7085f4d9dcc84e04561ee7ad067bf52e0f9b02e3209/ruff-0.14.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6be02e849440ed3602d2eb478ff7ff07d53e3758f7948a2a598829660988619e", size = 13412230, upload-time = "2025-11-28T20:55:12.749Z" }, + { url = "https://files.pythonhosted.org/packages/b7/4b/6e96cb6ba297f2ba502a231cd732ed7c3de98b1a896671b932a5eefa3804/ruff-0.14.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:19a0f116ee5e2b468dfe80c41c84e2bbd6b74f7b719bee86c2ecde0a34563bcc", size = 14195397, upload-time = "2025-11-28T20:54:56.896Z" }, + { url = "https://files.pythonhosted.org/packages/69/82/251d5f1aa4dcad30aed491b4657cecd9fb4274214da6960ffec144c260f7/ruff-0.14.7-py3-none-win32.whl", hash = "sha256:e33052c9199b347c8937937163b9b149ef6ab2e4bb37b042e593da2e6f6cccfa", size = 13126751, upload-time = "2025-11-28T20:55:03.47Z" }, + { url = "https://files.pythonhosted.org/packages/a8/b5/d0b7d145963136b564806f6584647af45ab98946660d399ec4da79cae036/ruff-0.14.7-py3-none-win_amd64.whl", hash = "sha256:e17a20ad0d3fad47a326d773a042b924d3ac31c6ca6deb6c72e9e6b5f661a7c6", size = 14531726, upload-time = "2025-11-28T20:54:59.121Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d2/1637f4360ada6a368d3265bf39f2cf737a0aaab15ab520fc005903e883f8/ruff-0.14.7-py3-none-win_arm64.whl", hash = "sha256:be4d653d3bea1b19742fcc6502354e32f65cd61ff2fbdb365803ef2c2aec6228", size = 13609215, upload-time = "2025-11-28T20:55:15.375Z" }, +] + +[[package]] +name = "sentry-sdk" +version = "2.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/d7/c140a5837649e2bf2ec758494fde1d9a016c76777eab64e75ef38d685bbb/sentry_sdk-2.46.0.tar.gz", hash = "sha256:91821a23460725734b7741523021601593f35731808afc0bb2ba46c27b8acd91", size = 374761, upload-time = "2025-11-24T09:34:13.932Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/b6/ce7c502a366f4835b1f9c057753f6989a92d3c70cbadb168193f5fb7499b/sentry_sdk-2.46.0-py2.py3-none-any.whl", hash = "sha256:4eeeb60198074dff8d066ea153fa6f241fef1668c10900ea53a4200abc8da9b1", size = 406266, upload-time = "2025-11-24T09:34:12.114Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sqlparse" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/90/76/437d71068094df0726366574cf3432a4ed754217b436eb7429415cf2d480/sqlparse-0.5.5.tar.gz", hash = "sha256:e20d4a9b0b8585fdf63b10d30066c7c94c5d7a7ec47c889a2d83a3caa93ff28e", size = 120815, upload-time = "2025-12-19T07:17:45.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/49/4b/359f28a903c13438ef59ebeee215fb25da53066db67b305c125f1c6d2a25/sqlparse-0.5.5-py3-none-any.whl", hash = "sha256:12a08b3bf3eec877c519589833aed092e2444e68240a3577e8e26148acc7b1ba", size = 46138, upload-time = "2025-12-19T07:17:46.573Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "tomlkit" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "types-requests" +version = "2.32.4.20250913" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/36/27/489922f4505975b11de2b5ad07b4fe1dca0bca9be81a703f26c5f3acfce5/types_requests-2.32.4.20250913.tar.gz", hash = "sha256:abd6d4f9ce3a9383f269775a9835a4c24e5cd6b9f647d64f88aa4613c33def5d", size = 23113, upload-time = "2025-09-13T02:40:02.309Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2a/20/9a227ea57c1285986c4cf78400d0a91615d25b24e257fd9e2969606bdfae/types_requests-2.32.4.20250913-py3-none-any.whl", hash = "sha256:78c9c1fffebbe0fa487a418e0fa5252017e9c60d1a2da394077f1780f655d7e1", size = 20658, upload-time = "2025-09-13T02:40:01.115Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5e/a7/c202b344c5ca7daf398f3b8a477eeb205cf3b6f32e7ec3a6bac0629ca975/tzdata-2025.3.tar.gz", hash = "sha256:de39c2ca5dc7b0344f2eba86f49d614019d29f060fc4ebc8a417896a620b56a7", size = 196772, upload-time = "2025-12-13T17:45:35.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/b0/003792df09decd6849a5e39c28b513c06e84436a54440380862b5aeff25d/tzdata-2025.3-py2.py3-none-any.whl", hash = "sha256:06a47e5700f3081aab02b2e513160914ff0694bce9947d6b76ebd6bf57cfc5d1", size = 348521, upload-time = "2025-12-13T17:45:33.889Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + +[[package]] +name = "uritemplate" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/60/f174043244c5306c9988380d2cb10009f91563fc4b31293d27e17201af56/uritemplate-4.2.0.tar.gz", hash = "sha256:480c2ed180878955863323eea31b0ede668795de182617fef9c6ca09e6ec9d0e", size = 33267, upload-time = "2025-06-02T15:12:06.318Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/99/3ae339466c9183ea5b8ae87b34c0b897eda475d2aec2307cae60e5cd4f29/uritemplate-4.2.0-py3-none-any.whl", hash = "sha256:962201ba1c4edcab02e60f9a0d3821e82dfc5d2d6662a21abd533879bdb8a686", size = 11488, upload-time = "2025-06-02T15:12:03.405Z" }, +] + +[[package]] +name = "url-normalize" +version = "2.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/80/31/febb777441e5fcdaacb4522316bf2a527c44551430a4873b052d545e3279/url_normalize-2.2.1.tar.gz", hash = "sha256:74a540a3b6eba1d95bdc610c24f2c0141639f3ba903501e61a52a8730247ff37", size = 18846, upload-time = "2025-04-26T20:37:58.553Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/d9/5ec15501b675f7bc07c5d16aa70d8d778b12375686b6efd47656efdc67cd/url_normalize-2.2.1-py3-none-any.whl", hash = "sha256:3deb687587dc91f7b25c9ae5162ffc0f057ae85d22b1e15cf5698311247f567b", size = 14728, upload-time = "2025-04-26T20:37:57.217Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/24/a2a2ed9addd907787d7aa0355ba36a6cadf1768b934c652ea78acbd59dcd/urllib3-2.6.2.tar.gz", hash = "sha256:016f9c98bb7e98085cb2b4b17b87d2c702975664e4f060c6532e64d1c1a5e797", size = 432930, upload-time = "2025-12-11T15:56:40.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/b9/4095b668ea3678bf6a0af005527f39de12fb026516fb3df17495a733b7f8/urllib3-2.6.2-py3-none-any.whl", hash = "sha256:ec21cddfe7724fc7cb4ba4bea7aa8e2ef36f607a4bab81aa6ce42a13dc3f03dd", size = 131182, upload-time = "2025-12-11T15:56:38.584Z" }, +] + +[[package]] +name = "urllib3-future" +version = "2.15.901" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, + { name = "jh2" }, + { name = "qh3", marker = "(platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'armv7l' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'i686' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'ppc64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'ppc64le' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'riscv64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'riscv64gc' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 's390x' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'darwin') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'armv7l' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'i686' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'ppc64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'ppc64le' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'riscv64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'riscv64gc' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 's390x' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'x86' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'linux') or (platform_machine == 'AMD64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ARM64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'aarch64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'arm64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'armv7l' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'i686' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ppc64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'ppc64le' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'riscv64' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'riscv64gc' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 's390x' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'x86' and platform_python_implementation == 'CPython' and sys_platform == 'win32') or (platform_machine == 'x86_64' and platform_python_implementation == 'CPython' and sys_platform == 'win32')" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/3d/ea375148eb25560c93a9cca9d7e23061150641f6c641c03d4d76bbc9d0a2/urllib3_future-2.15.901.tar.gz", hash = "sha256:a8ca77c6a3c8c1172511f45ba4358d2a682474580f75b2d234b1e427c58c922f", size = 1116237, upload-time = "2025-12-22T07:53:55.453Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/f9/3abec381843b5abbf2ce2cfd14b643c1c7808bdc1389aa13dd4fb378b454/urllib3_future-2.15.901-py3-none-any.whl", hash = "sha256:e88e2a835a4b75fd3dc4e9ccb3ba71e1000a8a98a43e0975e1d5be652beb2507", size = 684722, upload-time = "2025-12-22T07:53:53.694Z" }, +] + +[[package]] +name = "vine" +version = "5.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bd/e4/d07b5f29d283596b9727dd5275ccbceb63c44a1a82aa9e4bfd20426762ac/vine-5.1.0.tar.gz", hash = "sha256:8b62e981d35c41049211cf62a0a1242d8c1ee9bd15bb196ce38aefd6799e61e0", size = 48980, upload-time = "2023-11-05T08:46:53.857Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/03/ff/7c0c86c43b3cbb927e0ccc0255cb4057ceba4799cd44ae95174ce8e8b5b2/vine-5.1.0-py3-none-any.whl", hash = "sha256:40fdf3c48b2cfe1c38a49e9ae2da6fda88e4794c810050a728bd7413811fb1dc", size = 9636, upload-time = "2023-11-05T08:46:51.205Z" }, +] + +[[package]] +name = "wassima" +version = "2.0.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/1a/992d314e789b41513a285d28a4268cd9228a029a7913d976575f174d8c13/wassima-2.0.3.tar.gz", hash = "sha256:f86578e33e46e12352964ced83ec5a739ff77791e96224f980a043fa5ac563e8", size = 149031, upload-time = "2025-12-16T07:27:37.192Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/b1/52cb74011569cbc57dae499ed8d317098976bd22246b0e464282d3c1651f/wassima-2.0.3-py3-none-any.whl", hash = "sha256:019e0810ca643c5a63fe6f0a46c9a660200abd9588c07ba1fdff2545ade2aa1c", size = 144270, upload-time = "2025-12-16T07:27:35.735Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" }, +] + +[[package]] +name = "whitenoise" +version = "6.11.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/15/95/8c81ec6b6ebcbf8aca2de7603070ccf37dbb873b03f20708e0f7c1664bc6/whitenoise-6.11.0.tar.gz", hash = "sha256:0f5bfce6061ae6611cd9396a8231e088722e4fc67bc13a111be74c738d99375f", size = 26432, upload-time = "2025-09-18T09:16:10.995Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6c/e9/4366332f9295fe0647d7d3251ce18f5615fbcb12d02c79a26f8dba9221b3/whitenoise-6.11.0-py3-none-any.whl", hash = "sha256:b2aeb45950597236f53b5342b3121c5de69c8da0109362aee506ce88e022d258", size = 20197, upload-time = "2025-09-18T09:16:09.754Z" }, +] + +[[package]] +name = "x-wr-timezone" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "icalendar" }, + { name = "tzdata" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/79/2b/8ae5f59ab852c8fe32dd37c1aa058eb98aca118fec2d3af5c3cd56fffb7b/x_wr_timezone-2.0.1.tar.gz", hash = "sha256:9166c40e6ffd4c0edebabc354e1a1e2cffc1bb473f88007694793757685cc8c3", size = 18212, upload-time = "2025-02-06T17:10:40.913Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/b7/4bac35b4079b76c07d8faddf89467e9891b1610cfe8d03b0ebb5610e4423/x_wr_timezone-2.0.1-py3-none-any.whl", hash = "sha256:e74a53b9f4f7def8138455c240e65e47c224778bce3c024fcd6da2cbe91ca038", size = 11102, upload-time = "2025-02-06T17:10:39.192Z" }, +] diff --git a/src/frontend/.dockerignore b/src/frontend/.dockerignore new file mode 100644 index 0000000..ec39f24 --- /dev/null +++ b/src/frontend/.dockerignore @@ -0,0 +1,29 @@ + +# System-specific files +.DS_Store +**/.DS_Store + +# Docker +compose.* +env.d + +# Docs +docs +*.md +*.log + +# Development/test cache & configurations +data +.cache +.circleci +.git +.vscode +.iml +.idea +db.sqlite3 +.mypy_cache +.pylint.d +.pytest_cache + +# Frontend +node_modules diff --git a/src/frontend/Dockerfile b/src/frontend/Dockerfile new file mode 100644 index 0000000..19d9d59 --- /dev/null +++ b/src/frontend/Dockerfile @@ -0,0 +1,72 @@ +FROM node:22-alpine AS frontend-deps + +WORKDIR /home/frontend/ + +COPY ./package.json ./package.json +COPY ./yarn.lock ./yarn.lock +COPY ./apps/calendars/package.json ./apps/calendars/package.json +COPY ./packages/open-calendar/package.json ./packages/open-calendar/package.json + +RUN yarn install --frozen-lockfile + +COPY .dockerignore ./.dockerignore +# COPY ./.prettierrc.js ./.prettierrc.js +#COPY ./packages/eslint-config-calendars ./packages/eslint-config-calendars +COPY ./packages/open-calendar ./packages/open-calendar +COPY ./apps/calendars ./apps/calendars + +# Build open-calendar package +WORKDIR /home/frontend/packages/open-calendar +RUN yarn build +WORKDIR /home/frontend + +### ---- Front-end builder image ---- +FROM frontend-deps AS calendars + +WORKDIR /home/frontend/apps/calendars + +FROM frontend-deps AS calendars-dev + +WORKDIR /home/frontend/apps/calendars + +EXPOSE 3000 + +RUN yarn build-theme + +# Build open-calendar package if dist doesn't exist, then start dev server +CMD ["/bin/sh", "-c", "cd /home/frontend/packages/open-calendar && ([ -d dist ] || yarn build) && cd /home/frontend/apps/calendars && yarn dev"] + +# Tilt will rebuild calendars target so, we dissociate calendars and calendars-builder +# to avoid rebuilding the app at every changes. +FROM calendars AS calendars-builder + +WORKDIR /home/frontend/apps/calendars + +ARG API_ORIGIN +ENV NEXT_PUBLIC_API_ORIGIN=${API_ORIGIN} + +RUN yarn build + +# ---- Front-end image ---- +FROM nginxinc/nginx-unprivileged:alpine3.22 AS frontend-production + +# Upgrade system packages to install security updates +USER root +RUN apk update && \ + apk upgrade && \ + rm -rf /var/cache/apk/* + +# Un-privileged user running the application +ARG DOCKER_USER +USER ${DOCKER_USER} + +COPY --from=calendars-builder \ + /home/frontend/apps/calendars/out \ + /usr/share/nginx/html + +COPY ./apps/calendars/conf/default.conf /etc/nginx/conf.d +COPY ./docker/files/usr/local/bin/entrypoint /usr/local/bin/entrypoint + +ENTRYPOINT [ "/usr/local/bin/entrypoint" ] + +CMD ["nginx", "-g", "daemon off;"] diff --git a/src/frontend/apps/calendars/.env b/src/frontend/apps/calendars/.env new file mode 100644 index 0000000..8f22306 --- /dev/null +++ b/src/frontend/apps/calendars/.env @@ -0,0 +1 @@ +NEXT_PUBLIC_API_ORIGIN= \ No newline at end of file diff --git a/src/frontend/apps/calendars/.env.development b/src/frontend/apps/calendars/.env.development new file mode 100644 index 0000000..73c257c --- /dev/null +++ b/src/frontend/apps/calendars/.env.development @@ -0,0 +1 @@ +NEXT_PUBLIC_API_ORIGIN=http://localhost:8921 diff --git a/src/frontend/apps/calendars/.gitignore b/src/frontend/apps/calendars/.gitignore new file mode 100644 index 0000000..6fc1b4d --- /dev/null +++ b/src/frontend/apps/calendars/.gitignore @@ -0,0 +1,41 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/src/frontend/apps/calendars/README.md b/src/frontend/apps/calendars/README.md new file mode 100644 index 0000000..ef0e47e --- /dev/null +++ b/src/frontend/apps/calendars/README.md @@ -0,0 +1,40 @@ +This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/pages/api-reference/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +# or +pnpm dev +# or +bun dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/pages/building-your-application/routing/api-routes) instead of React pages. + +This project uses [`next/font`](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn-pages-router) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/pages/building-your-application/deploying) for more details. diff --git a/src/frontend/apps/calendars/__mocks__/fileMock.js b/src/frontend/apps/calendars/__mocks__/fileMock.js new file mode 100644 index 0000000..57a4949 --- /dev/null +++ b/src/frontend/apps/calendars/__mocks__/fileMock.js @@ -0,0 +1,2 @@ +module.exports = "test-file-stub"; + diff --git a/src/frontend/apps/calendars/conf/default.conf b/src/frontend/apps/calendars/conf/default.conf new file mode 100644 index 0000000..ed0be68 --- /dev/null +++ b/src/frontend/apps/calendars/conf/default.conf @@ -0,0 +1,26 @@ +server { + listen 8080; + listen 3000; + server_name localhost; + + root /usr/share/nginx/html; + + add_header X-Frame-Options DENY always; + + location / { + try_files $uri index.html $uri/ =404; + } + + location ~ "^/401/?$" { + try_files $uri /401.html; + } + + location ~ "^/403/?$" { + try_files $uri /403.html; + } + + error_page 404 /404.html; + location = /404.html { + internal; + } +} diff --git a/src/frontend/apps/calendars/cunningham.ts b/src/frontend/apps/calendars/cunningham.ts new file mode 100644 index 0000000..7e13183 --- /dev/null +++ b/src/frontend/apps/calendars/cunningham.ts @@ -0,0 +1,411 @@ +import { cunninghamConfig } from "@gouvfr-lasuite/ui-kit"; + +// TODO: Temporary solution to override the default button tertiary text color, waiting for the new ui-kit to be released + +/** + * Deep merge function that recursively merges objects + * @param target - The target object to merge into + * @param source - The source object to merge from + * @returns A new object with deeply merged properties + * + * @example + * const obj1 = { a: { x: 1, y: 2 }, b: 3 }; + * const obj2 = { a: { y: 3, z: 4 }, c: 5 }; + * const merged = deepMerge(obj1, obj2); + * // Result: { a: { x: 1, y: 3, z: 4 }, b: 3, c: 5 } + */ +// eslint-disable-next-line @typescript-eslint/no-explicit-any +function deepMerge(target: any, source: any): any { + const result = { ...target }; + + for (const key in source) { + if (source.hasOwnProperty(key)) { + const sourceValue = source[key]; + const targetValue = result[key]; + + if ( + sourceValue && + typeof sourceValue === "object" && + !Array.isArray(sourceValue) && + targetValue && + typeof targetValue === "object" && + !Array.isArray(targetValue) + ) { + // Recursively merge nested objects + result[key] = deepMerge(targetValue, sourceValue); + } else if (sourceValue !== undefined) { + // Override with source value + result[key] = sourceValue; + } + } + } + + return result; +} + +const themesImages = { + anct: { + favicon: "/assets/anct_favicon.png", + logo: "/assets/anct_logo_beta.svg", + "logo-icon": "/assets/anct_logo-icon.svg", + }, + dark: { + favicon: "/assets/favicon.png", + logo: "/assets/logo_beta.svg", + "logo-icon": "/assets/logo-icon_beta.svg", + }, + default: { + favicon: "/assets/favicon.png", + logo: "/assets/logo_beta.svg", + "logo-icon": "/assets/logo-icon_beta.svg", + }, +}; + +const themesGaufre = { + anct: { + widgetPath: "https://static.suite.anct.gouv.fr/widgets/lagaufre.js", + apiUrl: + "https://operateurs.suite.anct.gouv.fr/api/v1.0/lagaufre/services/?operator=9f5624fc-ef99-4d10-ae3f-403a81eb16ef&siret=21870030000013", + }, + dark: { + widgetPath: "https://static.suite.anct.gouv.fr/widgets/lagaufre.js", + apiUrl: "https://lasuite.numerique.gouv.fr/api/services", + }, + default: { + widgetPath: "https://static.suite.anct.gouv.fr/widgets/lagaufre.js", + apiUrl: "https://lasuite.numerique.gouv.fr/api/services", + }, +}; + +const getComponents = (theme: keyof typeof themesImages) => { + return { + datagrid: { + "body--background-color-hover": + "ref(contextuals.background.semantic.contextual.primary)", + }, + gaufre: { + widgetPath: `'${themesGaufre[theme].widgetPath}'`, + apiUrl: `'${themesGaufre[theme].apiUrl}'`, + }, + favicon: { + src: `'${themesImages[theme].favicon}'`, + }, + logo: { + src: `url('${themesImages[theme].logo}')`, + }, + "logo-icon": { + src: `url('${themesImages[theme]["logo-icon"]}')`, + }, + }; +}; + +const defaultConfig = deepMerge(cunninghamConfig, { + themes: { + anct: { + globals: { + colors: { + "brand-050": "#EEF0F9", + "brand-100": "#DDE2F5", + "brand-150": "#CBD4F1", + "brand-200": "#B8C6F0", + "brand-250": "#A5B7F2", + "brand-300": "#91A8F7", + "brand-350": "#7C98FE", + "brand-400": "#6A89FF", + "brand-450": "#5A7AFB", + "brand-500": "#4B6BF0", + "brand-550": "#3E5CE7", + "brand-600": "#3352D5", + "brand-650": "#2A47C0", + "brand-700": "#2340A3", + "brand-750": "#223A7F", + "brand-800": "#1F325F", + "brand-850": "#1B2845", + "brand-900": "#151E30", + "brand-950": "#0D121D", + "gray-000": "#FFFFFF", + "gray-025": "#F6F8FA", + "gray-050": "#ECF1F7", + "gray-100": "#DDE3F3", + "gray-150": "#CCD4EA", + "gray-200": "#BCC7E0", + "gray-250": "#AEB9D2", + "gray-300": "#A1ABC4", + "gray-350": "#949EB6", + "gray-400": "#8791A9", + "gray-450": "#7A849B", + "gray-500": "#6D778E", + "gray-550": "#616A81", + "gray-600": "#555E75", + "gray-650": "#495268", + "gray-700": "#3E475C", + "gray-750": "#333B50", + "gray-800": "#283044", + "gray-850": "#1E2539", + "gray-900": "#171B28", + "gray-950": "#0F1118", + "gray-1000": "#000000", + "info-050": "#E9F2F8", + "info-100": "#D2E5F1", + "info-150": "#C0D7F0", + "info-200": "#AEC8F0", + "info-250": "#9EB9F2", + "info-300": "#8DABEE", + "info-350": "#7B9DE9", + "info-400": "#6E8FDB", + "info-450": "#6282CD", + "info-500": "#5575BF", + "info-550": "#4968B1", + "info-600": "#3E5CA3", + "info-650": "#344F97", + "info-700": "#294389", + "info-750": "#243972", + "info-800": "#1D2F5B", + "info-850": "#1A2744", + "info-900": "#151D2F", + "info-950": "#0E131F", + "success-050": "#E7F1E9", + "success-100": "#CFE3D3", + "success-150": "#B9D8C0", + "success-200": "#A1CEAC", + "success-250": "#85C496", + "success-300": "#63BC7F", + "success-350": "#45B16B", + "success-400": "#1CA659", + "success-450": "#00984C", + "success-500": "#008A3F", + "success-550": "#007C32", + "success-600": "#006E24", + "success-650": "#016016", + "success-700": "#005305", + "success-750": "#0D450A", + "success-800": "#11380E", + "success-850": "#132A11", + "success-900": "#101E0F", + "success-950": "#091209", + "warning-050": "#F6F0E8", + "warning-100": "#EDE2D1", + "warning-150": "#E6D3B8", + "warning-200": "#E3C39F", + "warning-250": "#E3B082", + "warning-300": "#E19E5C", + "warning-350": "#D98E3F", + "warning-400": "#CF7D19", + "warning-450": "#C17000", + "warning-500": "#B36300", + "warning-550": "#A45600", + "warning-600": "#964900", + "warning-650": "#893C00", + "warning-700": "#7B2F00", + "warning-750": "#68270D", + "warning-800": "#562013", + "warning-850": "#411D18", + "warning-900": "#2E1714", + "warning-950": "#1D0F0D", + "error-050": "#F9EFEC", + "error-100": "#F4DFD9", + "error-150": "#F0CEC6", + "error-200": "#EEBCB2", + "error-250": "#EEA99D", + "error-300": "#EF9487", + "error-350": "#F37C6E", + "error-400": "#F65F53", + "error-450": "#EF443C", + "error-500": "#E0342E", + "error-550": "#D0201F", + "error-600": "#C0000C", + "error-650": "#AA0000", + "error-700": "#910C06", + "error-750": "#731E16", + "error-800": "#58201A", + "error-850": "#411D18", + "error-900": "#2E1714", + "error-950": "#1D0F0D", + "red-050": "#F9EFEC", + "red-100": "#F4DEDA", + "red-150": "#F0CDC9", + "red-200": "#EEBBB6", + "red-250": "#EEA8A2", + "red-300": "#F0938D", + "red-350": "#EC7E78", + "red-400": "#E46D67", + "red-450": "#D95B58", + "red-500": "#CA4E4B", + "red-550": "#BB403F", + "red-600": "#AC3233", + "red-650": "#9D2227", + "red-700": "#882023", + "red-750": "#721D1B", + "red-800": "#58201A", + "red-850": "#401D18", + "red-900": "#2E1714", + "red-950": "#1D0F0D", + "orange-050": "#F8F0E9", + "orange-100": "#F1E0D3", + "orange-150": "#ECD0BD", + "orange-200": "#E9C0A5", + "orange-250": "#E8AE8A", + "orange-300": "#EB9870", + "orange-350": "#EB845A", + "orange-400": "#E66E37", + "orange-450": "#DD5B16", + "orange-500": "#CE4D00", + "orange-550": "#BF3E00", + "orange-600": "#B02F00", + "orange-650": "#A11E00", + "orange-700": "#8A1E14", + "orange-750": "#731E16", + "orange-800": "#58201A", + "orange-850": "#401D18", + "orange-900": "#2E1714", + "orange-950": "#1D0F0D", + "brown-050": "#F5F0E8", + "brown-100": "#ECE2D1", + "brown-150": "#E9D1B9", + "brown-200": "#E3C19D", + "brown-250": "#DCB187", + "brown-300": "#D2A26F", + "brown-350": "#C49562", + "brown-400": "#B68855", + "brown-450": "#A97B48", + "brown-500": "#9B6E3B", + "brown-550": "#8E612F", + "brown-600": "#815521", + "brown-650": "#744913", + "brown-700": "#673D00", + "brown-750": "#5A3100", + "brown-800": "#4E2600", + "brown-850": "#3D1F0B", + "brown-900": "#2C170F", + "brown-950": "#1C0F0B", + "yellow-050": "#F3F0E7", + "yellow-100": "#E9E2CF", + "yellow-150": "#E0D4B7", + "yellow-200": "#DAC59A", + "yellow-250": "#D5B67A", + "yellow-300": "#D0A559", + "yellow-350": "#CC9331", + "yellow-400": "#C48400", + "yellow-450": "#B77600", + "yellow-500": "#AA6800", + "yellow-550": "#9D5A00", + "yellow-600": "#914D00", + "yellow-650": "#843F00", + "yellow-700": "#773200", + "yellow-750": "#6A2601", + "yellow-800": "#56210F", + "yellow-850": "#401D16", + "yellow-900": "#2E1714", + "yellow-950": "#1D0F0D", + "green-050": "#E3F1EF", + "green-100": "#CAE5E1", + "green-150": "#B0DBD4", + "green-200": "#91D1C7", + "green-250": "#6AC8BC", + "green-300": "#4DBCAF", + "green-350": "#3CAFA2", + "green-400": "#2AA194", + "green-450": "#109487", + "green-500": "#00867A", + "green-550": "#00786D", + "green-600": "#016A60", + "green-650": "#015D53", + "green-700": "#005047", + "green-750": "#00443B", + "green-800": "#00382F", + "green-850": "#002C25", + "green-900": "#041F1A", + "green-950": "#041310", + "blue1-050": "#EAF2F9", + "blue1-100": "#D4E4F3", + "blue1-150": "#BFD7F0", + "blue1-200": "#AAC9EF", + "blue1-250": "#96BBF1", + "blue1-300": "#82ACF6", + "blue1-350": "#709BFE", + "blue1-400": "#608BFF", + "blue1-450": "#537BFB", + "blue1-500": "#476DEC", + "blue1-550": "#3C60DD", + "blue1-600": "#3252CF", + "blue1-650": "#2B48B9", + "blue1-700": "#28409B", + "blue1-750": "#24397E", + "blue1-800": "#223260", + "blue1-850": "#1F2A48", + "blue1-900": "#191F32", + "blue1-950": "#111320", + "blue2-050": "#E5F2F3", + "blue2-100": "#CDE6EC", + "blue2-150": "#B7D9EA", + "blue2-200": "#9BCDE7", + "blue2-250": "#84C1E0", + "blue2-300": "#6BB4D8", + "blue2-350": "#5CA6CB", + "blue2-400": "#4D99BC", + "blue2-450": "#3E8CAE", + "blue2-500": "#2F7FA2", + "blue2-550": "#1F7295", + "blue2-600": "#056688", + "blue2-650": "#00597B", + "blue2-700": "#004C6C", + "blue2-750": "#003F5E", + "blue2-800": "#003353", + "blue2-850": "#0C273E", + "blue2-900": "#0E1C2C", + "blue2-950": "#0A121C", + "purple-050": "#EDF1FA", + "purple-100": "#DCE2F5", + "purple-150": "#CCD4F1", + "purple-200": "#BCC4F0", + "purple-250": "#ADB6F2", + "purple-300": "#9EA6F6", + "purple-350": "#8E95FD", + "purple-400": "#8083FF", + "purple-450": "#7173FF", + "purple-500": "#6665F1", + "purple-550": "#5B57E2", + "purple-600": "#5049D4", + "purple-650": "#4641BC", + "purple-700": "#3D39A2", + "purple-750": "#363680", + "purple-800": "#2E3162", + "purple-850": "#242848", + "purple-900": "#1C1E32", + "purple-950": "#121320", + "pink-050": "#F8EFF4", + "pink-100": "#F0DEE9", + "pink-150": "#EBCDDF", + "pink-200": "#E7BDD6", + "pink-250": "#E5A9CC", + "pink-300": "#E695C0", + "pink-350": "#EA7CAE", + "pink-400": "#E4659F", + "pink-450": "#DD4F93", + "pink-500": "#CD4085", + "pink-550": "#BE3279", + "pink-600": "#AE216D", + "pink-650": "#9B195D", + "pink-700": "#86164E", + "pink-750": "#6E1B3D", + "pink-800": "#551E31", + "pink-850": "#3F1C24", + "pink-900": "#2D161A", + "pink-950": "#1C0E10", + }, + }, + components: getComponents("anct"), + }, + dark: { + globals: cunninghamConfig.themes.default.globals, + components: getComponents("dark"), + }, + default: { + components: getComponents("default"), + }, + }, +}); + +const config = defaultConfig; + +export default config; diff --git a/src/frontend/apps/calendars/eslint.config.mjs b/src/frontend/apps/calendars/eslint.config.mjs new file mode 100644 index 0000000..93ffbd0 --- /dev/null +++ b/src/frontend/apps/calendars/eslint.config.mjs @@ -0,0 +1,22 @@ +import { dirname } from "path"; +import { fileURLToPath } from "url"; +import { FlatCompat } from "@eslint/eslintrc"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const compat = new FlatCompat({ + baseDirectory: __dirname, +}); + +const eslintConfig = [ + ...compat.extends("next/core-web-vitals", "next/typescript"), + { + rules: { + "react-hooks/exhaustive-deps": "off", + "@next/next/no-img-element": "off", + }, + }, +]; + +export default eslintConfig; diff --git a/src/frontend/apps/calendars/jest.config.ts b/src/frontend/apps/calendars/jest.config.ts new file mode 100644 index 0000000..8f83dcd --- /dev/null +++ b/src/frontend/apps/calendars/jest.config.ts @@ -0,0 +1,39 @@ +import type { Config } from "jest"; +import { pathsToModuleNameMapper } from "ts-jest"; +import tsconfig from "./tsconfig.json"; + +const config: Config = { + preset: "ts-jest", + testEnvironment: "node", + roots: ["/src"], + testMatch: ["**/__tests__/**/*.test.ts", "**/__tests__/**/*.test.tsx"], + moduleNameMapper: { + // Handle static assets FIRST (before path aliases) + "\\.(css|less|scss|sass|svg|png|jpg|jpeg|gif)$": + "/__mocks__/fileMock.js", + // Then handle path aliases + ...pathsToModuleNameMapper(tsconfig.compilerOptions.paths || {}, { + prefix: "/", + }), + }, + transform: { + "^.+\\.(ts|tsx)$": [ + "ts-jest", + { + tsconfig: { + jsx: "react", + moduleResolution: "node", + }, + }, + ], + }, + transformIgnorePatterns: ["node_modules/(?!(.*\\.mjs$))"], + moduleFileExtensions: ["ts", "tsx", "js", "jsx", "json", "svg"], + collectCoverageFrom: [ + "src/**/*.{ts,tsx}", + "!src/**/*.d.ts", + "!src/**/__tests__/**", + ], +}; + +export default config; diff --git a/src/frontend/apps/calendars/next.config.ts b/src/frontend/apps/calendars/next.config.ts new file mode 100644 index 0000000..3cc9059 --- /dev/null +++ b/src/frontend/apps/calendars/next.config.ts @@ -0,0 +1,21 @@ +import type { NextConfig } from "next"; +import path from "path"; + +const nextConfig: NextConfig = { + output: "export", + debug: process.env.NODE_ENV === "development", + reactStrictMode: false, + webpack: (config, { isServer }) => { + // Resolve workspace packages + config.resolve.alias = { + ...config.resolve.alias, + "open-dav-calendar": path.resolve( + __dirname, + "../../packages/open-calendar/dist/index.js" + ), + }; + return config; + }, +}; + +export default nextConfig; diff --git a/src/frontend/apps/calendars/package.json b/src/frontend/apps/calendars/package.json new file mode 100644 index 0000000..5930bc2 --- /dev/null +++ b/src/frontend/apps/calendars/package.json @@ -0,0 +1,54 @@ +{ + "name": "calendars", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build --no-lint", + "start": "next start", + "lint": "next lint", + "build-theme": "cunningham -g css,scss,ts -o src/styles && mv src/styles/cunningham-tokens.scss src/styles/cunningham-tokens-sass.scss", + "test": "jest", + "test:watch": "jest --watch" + }, + "engines": { + "node": ">=22.0.0 <25.0.0", + "yarn": "1.22.22" + }, + "dependencies": { + "@gouvfr-lasuite/ui-kit": "0.18.4", + "@openfun/cunningham-react": "4.0.0", + "open-dav-calendar": "*", + "date-fns": "4.1.0", + "@tanstack/react-query": "5.90.10", + "@tanstack/react-table": "8.21.3", + "@viselect/react": "3.9.0", + "clsx": "2.1.1", + "i18next": "25.6.2", + "i18next-browser-languagedetector": "8.2.0", + "next": "15.4.9", + "next-i18next": "15.4.2", + "pretty-bytes": "7.1.0", + "react": "19.2.0", + "react-dom": "19.2.0", + "react-dropzone": "14.3.8", + "react-hook-form": "7.66.0", + "react-i18next": "16.3.3", + "react-toastify": "11.0.5", + "sass": "1.94.0" + }, + "devDependencies": { + "@tanstack/react-query-devtools": "5.66.9", + "@eslint/eslintrc": "3.2.0", + "@tanstack/eslint-plugin-query": "5.66.1", + "@types/jest": "29.5.14", + "@types/node": "24.10.1", + "@types/react": "19.2.5", + "@types/react-dom": "19.2.3", + "eslint": "9.20.1", + "eslint-config-next": "15.1.7", + "jest": "29.7.0", + "ts-jest": "29.2.5", + "typescript": "5.4.5" + } +} diff --git a/src/frontend/apps/calendars/public/assets/401-background.png b/src/frontend/apps/calendars/public/assets/401-background.png new file mode 100644 index 0000000..02c7c84 Binary files /dev/null and b/src/frontend/apps/calendars/public/assets/401-background.png differ diff --git a/src/frontend/apps/calendars/public/assets/403-background.png b/src/frontend/apps/calendars/public/assets/403-background.png new file mode 100644 index 0000000..480944f Binary files /dev/null and b/src/frontend/apps/calendars/public/assets/403-background.png differ diff --git a/src/frontend/apps/calendars/public/assets/anct_favicon.png b/src/frontend/apps/calendars/public/assets/anct_favicon.png new file mode 100644 index 0000000..dd96620 Binary files /dev/null and b/src/frontend/apps/calendars/public/assets/anct_favicon.png differ diff --git a/src/frontend/apps/calendars/public/assets/anct_logo-icon.svg b/src/frontend/apps/calendars/public/assets/anct_logo-icon.svg new file mode 100644 index 0000000..b1cabf7 --- /dev/null +++ b/src/frontend/apps/calendars/public/assets/anct_logo-icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/frontend/apps/calendars/public/assets/anct_logo_alpha.svg b/src/frontend/apps/calendars/public/assets/anct_logo_alpha.svg new file mode 100644 index 0000000..7d61b61 --- /dev/null +++ b/src/frontend/apps/calendars/public/assets/anct_logo_alpha.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/frontend/apps/calendars/public/assets/anct_logo_beta.svg b/src/frontend/apps/calendars/public/assets/anct_logo_beta.svg new file mode 100644 index 0000000..495e388 --- /dev/null +++ b/src/frontend/apps/calendars/public/assets/anct_logo_beta.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/apps/calendars/public/assets/favicon.png b/src/frontend/apps/calendars/public/assets/favicon.png new file mode 100644 index 0000000..adf6ce0 Binary files /dev/null and b/src/frontend/apps/calendars/public/assets/favicon.png differ diff --git a/src/frontend/apps/calendars/public/assets/logo-icon_alpha.svg b/src/frontend/apps/calendars/public/assets/logo-icon_alpha.svg new file mode 100644 index 0000000..ee47c74 --- /dev/null +++ b/src/frontend/apps/calendars/public/assets/logo-icon_alpha.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/src/frontend/apps/calendars/public/assets/logo-icon_beta.svg b/src/frontend/apps/calendars/public/assets/logo-icon_beta.svg new file mode 100644 index 0000000..55255e6 --- /dev/null +++ b/src/frontend/apps/calendars/public/assets/logo-icon_beta.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/frontend/apps/calendars/public/assets/logo-suite-numerique.png b/src/frontend/apps/calendars/public/assets/logo-suite-numerique.png new file mode 100644 index 0000000..840e972 Binary files /dev/null and b/src/frontend/apps/calendars/public/assets/logo-suite-numerique.png differ diff --git a/src/frontend/apps/calendars/public/assets/logo_alpha.svg b/src/frontend/apps/calendars/public/assets/logo_alpha.svg new file mode 100644 index 0000000..5411eb4 --- /dev/null +++ b/src/frontend/apps/calendars/public/assets/logo_alpha.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/frontend/apps/calendars/public/mime-video.svg b/src/frontend/apps/calendars/public/mime-video.svg new file mode 100644 index 0000000..4196808 --- /dev/null +++ b/src/frontend/apps/calendars/public/mime-video.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/apps/calendars/src/assets/feedback/form.svg b/src/frontend/apps/calendars/src/assets/feedback/form.svg new file mode 100644 index 0000000..6d1caeb --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/feedback/form.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/feedback/tchap.svg b/src/frontend/apps/calendars/src/assets/feedback/tchap.svg new file mode 100644 index 0000000..655df61 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/feedback/tchap.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/feedback/visio.svg b/src/frontend/apps/calendars/src/assets/feedback/visio.svg new file mode 100644 index 0000000..df54fea --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/feedback/visio.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/cancel.svg b/src/frontend/apps/calendars/src/assets/icons/cancel.svg new file mode 100644 index 0000000..3f1832d --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/cancel.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/cancel_blue.svg b/src/frontend/apps/calendars/src/assets/icons/cancel_blue.svg new file mode 100644 index 0000000..b92c720 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/cancel_blue.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/delete_filled.svg b/src/frontend/apps/calendars/src/assets/icons/delete_filled.svg new file mode 100644 index 0000000..2b7fd3f --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/delete_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/info.svg b/src/frontend/apps/calendars/src/assets/icons/info.svg new file mode 100644 index 0000000..e96fa00 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/info.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/settings.svg b/src/frontend/apps/calendars/src/assets/icons/settings.svg new file mode 100644 index 0000000..6dbec58 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/settings.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/trash.svg b/src/frontend/apps/calendars/src/assets/icons/trash.svg new file mode 100644 index 0000000..2b7fd3f --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/undo.svg b/src/frontend/apps/calendars/src/assets/icons/undo.svg new file mode 100644 index 0000000..6549735 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/undo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/icons/undo_blue.svg b/src/frontend/apps/calendars/src/assets/icons/undo_blue.svg new file mode 100644 index 0000000..a1effc4 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/icons/undo_blue.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/frontend/apps/calendars/src/assets/logo-gouv.svg b/src/frontend/apps/calendars/src/assets/logo-gouv.svg new file mode 100644 index 0000000..824e1b9 --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/logo-gouv.svg @@ -0,0 +1,454 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/frontend/apps/calendars/src/assets/logo-icon.svg b/src/frontend/apps/calendars/src/assets/logo-icon.svg new file mode 100644 index 0000000..6afd48a --- /dev/null +++ b/src/frontend/apps/calendars/src/assets/logo-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/frontend/apps/calendars/src/features/analytics/AnalyticsProvider.tsx b/src/frontend/apps/calendars/src/features/analytics/AnalyticsProvider.tsx new file mode 100644 index 0000000..6869518 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/analytics/AnalyticsProvider.tsx @@ -0,0 +1,7 @@ +export const AnalyticsProvider = ({ + children, +}: { + children: React.ReactNode; +}) => { + return <>{children}; +}; diff --git a/src/frontend/apps/calendars/src/features/api/APIError.ts b/src/frontend/apps/calendars/src/features/api/APIError.ts new file mode 100644 index 0000000..8942ebf --- /dev/null +++ b/src/frontend/apps/calendars/src/features/api/APIError.ts @@ -0,0 +1,57 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import i18n from "@/features/i18n/initI18n"; +import { AppError } from "../errors/AppError"; + +export class APIError extends Error { + data?: any; + code: number; + + constructor(code: number, data?: any) { + super(); + this.data = data; + this.code = code; + } +} + +export const errorToString = (error: unknown): string => { + if (typeof error === "string") { + return error; + } + + if (error instanceof APIError) { + const data = error.data; + // If there is a data, it means that the error is a JSON object + if (typeof data === "string") { + return data; + } + + if ( + data?.errors && + Array.isArray(data?.errors) && + data?.errors?.length > 0 + ) { + return data.errors[0].detail; + } + + if (data) { + /** + * This is made to handle full text errors from the API like: + * + * "title": [ + * "The title field is required." + * ] + */ + return Object.entries(error.data) + .map(([, value]) => `${value}`) + .join("\n"); + } + // If there is no data, it means that the error is a string, probably a complicated html error. + return i18n.t("api.error.unexpected"); + } + // We want to show the error message from the AppError only. Not message from the Error class as they + // can be really technical and not helpful for the user. For those we show the generic error message. + if (error instanceof AppError) { + return error.message; + } + return i18n.t("api.error.unexpected"); +}; diff --git a/src/frontend/apps/calendars/src/features/api/fetchApi.ts b/src/frontend/apps/calendars/src/features/api/fetchApi.ts new file mode 100644 index 0000000..d61c570 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/api/fetchApi.ts @@ -0,0 +1,67 @@ +import { baseApiUrl, isJson } from "./utils"; +import { APIError } from "./APIError"; + +/** + * Retrieves the CSRF token from the document's cookies. + * + * @returns {string|null} The CSRF token if found in the cookies, or null if not present. + */ +function getCSRFToken() { + return document.cookie + .split(";") + .filter((cookie) => cookie.trim().startsWith("csrftoken=")) + .map((cookie) => cookie.split("=")[1]) + .pop(); +} + +export const SESSION_STORAGE_REDIRECT_AFTER_LOGIN_URL = + "redirect_after_login_url"; + +const redirect = (url: string, saveRedirectAfterLoginUrl = true) => { + if (saveRedirectAfterLoginUrl) { + sessionStorage.setItem( + SESSION_STORAGE_REDIRECT_AFTER_LOGIN_URL, + window.location.href + ); + } + window.location.href = url; +}; + +export interface fetchAPIOptions { +} + +export const fetchAPI = async ( + input: string, + init?: RequestInit & { params?: Record }, + options?: fetchAPIOptions +) => { + const apiUrl = new URL(`${baseApiUrl("1.0")}${input}`); + if (init?.params) { + Object.entries(init.params).forEach(([key, value]) => { + apiUrl.searchParams.set(key, String(value)); + }); + } + const csrfToken = getCSRFToken(); + + const response = await fetch(apiUrl, { + ...init, + credentials: "include", + headers: { + ...init?.headers, + "Content-Type": "application/json", + ...(csrfToken && { "X-CSRFToken": csrfToken }), + }, + }); + + if (response.ok) { + return response; + } + + const data = await response.text(); + + if (isJson(data)) { + throw new APIError(response.status, JSON.parse(data)); + } + + throw new APIError(response.status); +}; diff --git a/src/frontend/apps/calendars/src/features/api/types.ts b/src/frontend/apps/calendars/src/features/api/types.ts new file mode 100644 index 0000000..a181a2b --- /dev/null +++ b/src/frontend/apps/calendars/src/features/api/types.ts @@ -0,0 +1,18 @@ +export interface ApiConfig { + FRONTEND_THEME?: string; + FRONTEND_HIDE_GAUFRE?: boolean; + FRONTEND_FEEDBACK_BUTTON_SHOW?: boolean; + FRONTEND_FEEDBACK_BUTTON_IDLE?: boolean; + FRONTEND_FEEDBACK_ITEMS?: Record; + FRONTEND_MORE_LINK?: string; + FRONTEND_FEEDBACK_MESSAGES_WIDGET_API_URL?: string; + FRONTEND_FEEDBACK_MESSAGES_WIDGET_PATH?: string; + FRONTEND_FEEDBACK_MESSAGES_WIDGET_CHANNEL?: string; + theme_customization?: ThemeCustomization; +} + +export interface ThemeCustomization { + footer?: Record; + [key: string]: unknown; +} + diff --git a/src/frontend/apps/calendars/src/features/api/utils.ts b/src/frontend/apps/calendars/src/features/api/utils.ts new file mode 100644 index 0000000..29838db --- /dev/null +++ b/src/frontend/apps/calendars/src/features/api/utils.ts @@ -0,0 +1,39 @@ +export const errorCauses = async (response: Response, data?: unknown) => { + const errorsBody = (await response.json()) as Record< + string, + string | string[] + > | null; + + const causes = errorsBody + ? Object.entries(errorsBody) + .map(([, value]) => value) + .flat() + : undefined; + + return { + status: response.status, + cause: causes, + data, + }; +}; + +export const getOrigin = () => { + return ( + process.env.NEXT_PUBLIC_API_ORIGIN || + (typeof window !== "undefined" ? window.location.origin : "") + ); +}; +export const baseApiUrl = (apiVersion: string = "1.0") => { + const origin = getOrigin(); + return `${origin}/api/v${apiVersion}/`; +}; + +export const isJson = (str: string) => { + try { + JSON.parse(str); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + } catch (e) { + return false; + } + return true; +}; diff --git a/src/frontend/apps/calendars/src/features/auth/Auth.tsx b/src/frontend/apps/calendars/src/features/auth/Auth.tsx new file mode 100644 index 0000000..24f34f3 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/auth/Auth.tsx @@ -0,0 +1,76 @@ +import React, { PropsWithChildren, useEffect, useState } from "react"; + +import { fetchAPI } from "@/features/api/fetchApi"; +import { User } from "@/features/auth/types"; +import { baseApiUrl } from "../api/utils"; +import { APIError } from "../api/APIError"; +import { SpinnerPage } from "@/features/ui/components/spinner/SpinnerPage"; + +export const logout = () => { + window.location.replace(new URL("logout/", baseApiUrl()).href); +}; + +export const login = (returnTo?: string) => { + const url = new URL("authenticate/", baseApiUrl()); + if (returnTo) { + url.searchParams.set("returnTo", returnTo); + } + window.location.replace(url.href); +}; + +interface AuthContextInterface { + user?: User | null; + init?: () => Promise; + refreshUser?: () => Promise; +} + +export const AuthContext = React.createContext({}); + +export const useAuth = () => React.useContext(AuthContext); + +export const Auth = ({ + children, + redirect, +}: PropsWithChildren & { redirect?: boolean }) => { + const [user, setUser] = useState(); + + const init = async () => { + try { + const response = await fetchAPI(`users/me/`); + const data = (await response.json()) as User; + setUser(data); + return data; + } catch (error) { + if (redirect && error instanceof APIError && error.code === 401) { + login(); + } else { + setUser(null); + } + return null; + } + }; + + const refreshUser = async () => { + void init(); + }; + + useEffect(() => { + void init(); + }, []); + + if (user === undefined) { + return ; + } + + return ( + + {children} + + ); +}; diff --git a/src/frontend/apps/calendars/src/features/auth/components/LoginButton.tsx b/src/frontend/apps/calendars/src/features/auth/components/LoginButton.tsx new file mode 100644 index 0000000..e0ac806 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/auth/components/LoginButton.tsx @@ -0,0 +1,23 @@ +import { Button } from "@openfun/cunningham-react"; +import { login } from "../Auth"; +import { useTranslation } from "react-i18next"; +import { SESSION_STORAGE_REDIRECT_AFTER_LOGIN_URL } from "@/features/api/fetchApi"; + +export const LoginButton = () => { + const { t } = useTranslation(); + return ( + + ); +}; diff --git a/src/frontend/apps/calendars/src/features/auth/components/LogoutButton.tsx b/src/frontend/apps/calendars/src/features/auth/components/LogoutButton.tsx new file mode 100644 index 0000000..145e86e --- /dev/null +++ b/src/frontend/apps/calendars/src/features/auth/components/LogoutButton.tsx @@ -0,0 +1,12 @@ +import { Button } from "@openfun/cunningham-react"; +import { logout } from "../Auth"; +import { useTranslation } from "react-i18next"; + +export const LogoutButton = () => { + const { t } = useTranslation(); + return ( + + ); +}; diff --git a/src/frontend/apps/calendars/src/features/auth/types.ts b/src/frontend/apps/calendars/src/features/auth/types.ts new file mode 100644 index 0000000..29093fc --- /dev/null +++ b/src/frontend/apps/calendars/src/features/auth/types.ts @@ -0,0 +1,12 @@ +/** + * Represents user retrieved from the API. + * @interface User + * @property {string} id - The id of the user. + * @property {string} email - The email of the user. + * @property {string} name - The name of the user. + */ +export interface User { + id: string; + email: string; + language: string; +} diff --git a/src/frontend/apps/calendars/src/features/calendar/api.ts b/src/frontend/apps/calendars/src/features/calendar/api.ts new file mode 100644 index 0000000..62c6799 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/api.ts @@ -0,0 +1,51 @@ +/** + * API functions for calendar operations. + */ + +import { fetchAPI } from "@/features/api/fetchApi"; + +export interface Calendar { + id: string; + name: string; + color: string; + description: string; + is_default: boolean; + is_visible: boolean; + owner: string; +} + + +/** + * Fetch all calendars accessible by the current user. + */ +export const getCalendars = async (): Promise => { + const response = await fetchAPI("calendars/"); + return response.json(); +}; + +/** + * Create a new calendar. + */ +export const createCalendar = async (data: { + name: string; + color?: string; +}): Promise => { + const response = await fetchAPI("calendars/", { + method: "POST", + body: JSON.stringify(data), + }); + return response.json(); +}; + +/** + * Toggle calendar visibility. + */ +export const toggleCalendarVisibility = async ( + calendarId: string +): Promise<{ is_visible: boolean }> => { + const response = await fetchAPI(`calendars/${calendarId}/toggle_visibility/`, { + method: "PATCH", + }); + return response.json(); +}; + diff --git a/src/frontend/apps/calendars/src/features/calendar/components/CalendarList.scss b/src/frontend/apps/calendars/src/features/calendar/components/CalendarList.scss new file mode 100644 index 0000000..c960800 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/CalendarList.scss @@ -0,0 +1,99 @@ +.calendar-list { + padding: 0.5rem 0.75rem; + + &__section { + margin-bottom: 1rem; + } + + &__section-header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 0.5rem; + } + + &__section-title { + font-size: 0.75rem; + font-weight: 600; + color: var(--c--theme--colors--greyscale-600); + text-transform: uppercase; + letter-spacing: 0.025em; + } + + &__add-btn { + display: flex; + align-items: center; + justify-content: center; + width: 1.5rem; + height: 1.5rem; + border: none; + background: transparent; + border-radius: 50%; + cursor: pointer; + color: var(--c--theme--colors--greyscale-600); + transition: background-color 0.15s, color 0.15s; + + &:hover { + background-color: var(--c--theme--colors--greyscale-100); + color: var(--c--theme--colors--primary-500); + } + + .material-icons { + font-size: 1.125rem; + } + } + + &__items { + display: flex; + flex-direction: column; + gap: 0.25rem; + } + + &__item { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.375rem 0.25rem; + border-radius: 4px; + transition: background-color 0.15s; + + &:hover { + background-color: var(--c--theme--colors--greyscale-50); + } + + // Override Cunningham checkbox styles for compact display + .c__checkbox { + margin: 0; + } + + .c__checkbox__multi-wrapper { + gap: 0; + } + } + + &__color { + width: 0.75rem; + height: 0.75rem; + border-radius: 2px; + flex-shrink: 0; + } + + &__name { + flex: 1; + font-size: 0.875rem; + color: var(--c--theme--colors--greyscale-800); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + &__badge { + font-size: 0.625rem; + padding: 0.125rem 0.375rem; + background-color: var(--c--theme--colors--greyscale-100); + color: var(--c--theme--colors--greyscale-600); + border-radius: 0.75rem; + text-transform: uppercase; + font-weight: 500; + } +} diff --git a/src/frontend/apps/calendars/src/features/calendar/components/CalendarList.tsx b/src/frontend/apps/calendars/src/features/calendar/components/CalendarList.tsx new file mode 100644 index 0000000..4554657 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/CalendarList.tsx @@ -0,0 +1,88 @@ +/** + * CalendarList component - List of calendars with visibility toggles. + */ + +import { Button, Checkbox } from "@openfun/cunningham-react"; + +import { Calendar } from "../api"; +import { useToggleCalendarVisibility } from "../hooks/useCalendars"; + +interface CalendarListProps { + calendars: Calendar[]; + onCreateCalendar: () => void; +} + +export const CalendarList = ({ + calendars, + onCreateCalendar, +}: CalendarListProps) => { + const toggleVisibility = useToggleCalendarVisibility(); + + // Ensure calendars is an array + const calendarsArray = Array.isArray(calendars) ? calendars : []; + + const ownedCalendars = calendarsArray.filter( + (cal) => !cal.name.includes("(partagé)") + ); + const sharedCalendars = calendarsArray.filter((cal) => + cal.name.includes("(partagé)") + ); + + const handleToggle = (calendarId: string) => { + toggleVisibility.mutate(calendarId); + }; + + const renderCalendarItem = (calendar: Calendar) => ( +
+ handleToggle(calendar.id)} + label="" + aria-label={`Afficher ${calendar.name}`} + /> + + + {calendar.name} + + {calendar.is_default && ( + Par défaut + )} +
+ ); + + return ( +
+
+
+ Mes calendriers + +
+
+ {ownedCalendars.map(renderCalendarItem)} +
+
+ + {sharedCalendars.length > 0 && ( +
+
+ + Calendriers partagés + +
+
+ {sharedCalendars.map(renderCalendarItem)} +
+
+ )} +
+ ); +}; diff --git a/src/frontend/apps/calendars/src/features/calendar/components/CalendarView.scss b/src/frontend/apps/calendars/src/features/calendar/components/CalendarView.scss new file mode 100644 index 0000000..c5646fe --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/CalendarView.scss @@ -0,0 +1,171 @@ +.calendar-view { + display: flex; + flex-direction: column; + flex: 1; + height: 100%; + min-height: 0; + position: relative; + + &__loading { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 10; + display: flex; + align-items: center; + justify-content: center; + padding: 1rem 2rem; + background: var(--c--theme--colors--greyscale-000); + border-radius: 8px; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + + p { + margin: 0; + color: var(--c--theme--colors--greyscale-600); + } + } + + &__container { + flex: 1; + min-height: 0; + overflow: hidden; + transition: opacity 0.3s ease; + } + + &--loading, + &--error { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + gap: 1rem; + padding: 2rem; + text-align: center; + + p { + color: var(--c--theme--colors--greyscale-600); + margin: 0; + } + + button { + padding: 0.5rem 1rem; + background: var(--c--theme--colors--primary-500); + color: white; + border: none; + border-radius: 4px; + cursor: pointer; + + &:hover { + background: var(--c--theme--colors--primary-600); + } + } + } +} + +// Open-calendar overrides to match La Suite theme +.calendar-view__container { + // Calendar toolbar + .ec-toolbar { + padding: 0.75rem 1rem; + border-bottom: 1px solid var(--c--theme--colors--greyscale-200); + background: var(--c--theme--colors--greyscale-000); + } + + // Today button + .ec-button { + padding: 0.375rem 0.75rem; + border-radius: 4px; + font-size: 0.875rem; + font-weight: 500; + border: 1px solid var(--c--theme--colors--greyscale-300); + background: var(--c--theme--colors--greyscale-000); + color: var(--c--theme--colors--greyscale-800); + cursor: pointer; + transition: all 0.2s ease; + + &:hover { + background: var(--c--theme--colors--greyscale-100); + } + + &.ec-active { + background: var(--c--theme--colors--primary-500); + border-color: var(--c--theme--colors--primary-500); + color: white; + } + } + + // Navigation buttons + .ec-prev, + .ec-next { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + } + + // Title + .ec-title { + font-size: 1.125rem; + font-weight: 600; + color: var(--c--theme--colors--greyscale-900); + text-transform: capitalize; + } + + // Days header + .ec-days, + .ec-day { + border-color: var(--c--theme--colors--greyscale-200); + } + + .ec-day-head { + padding: 0.5rem; + font-size: 0.75rem; + font-weight: 600; + text-transform: uppercase; + color: var(--c--theme--colors--greyscale-600); + } + + // Time slots + .ec-time { + font-size: 0.75rem; + color: var(--c--theme--colors--greyscale-500); + } + + // Events + .ec-event { + border-radius: 4px; + font-size: 0.75rem; + padding: 2px 4px; + border: none; + box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); + + &:hover { + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15); + } + } + + // Today highlight + .ec-today { + background: rgba(var(--c--theme--colors--primary-rgb, 49, 116, 173), 0.1); + } + + // Now indicator + .ec-now-indicator { + border-color: var(--c--theme--colors--danger-500); + + &::before { + background: var(--c--theme--colors--danger-500); + } + } + + // Popup styles + .ec-popup { + border-radius: 8px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); + border: 1px solid var(--c--theme--colors--greyscale-200); + } +} diff --git a/src/frontend/apps/calendars/src/features/calendar/components/CalendarView.tsx b/src/frontend/apps/calendars/src/features/calendar/components/CalendarView.tsx new file mode 100644 index 0000000..e7603e9 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/CalendarView.tsx @@ -0,0 +1,209 @@ +/** + * CalendarView component using open-calendar (Algoo). + * Renders a CalDAV-connected calendar view. + */ + +import { useEffect, useRef, useState } from "react"; + +import { useAuth } from "@/features/auth/Auth"; +import { createEventModalHandlers, type ModalState } from "./EventModalAdapter"; +import { useEventModal } from "../hooks/useEventModal"; +import type { IcsEvent } from 'ts-ics'; + +interface CalendarViewProps { + selectedDate?: Date; + onSelectDate?: (date: Date) => void; +} + +export const CalendarView = ({ + selectedDate = new Date(), + onSelectDate, +}: CalendarViewProps) => { + const containerRef = useRef(null); + const calendarRef = useRef(null); + const [isLoading, setIsLoading] = useState(true); + const [error, setError] = useState(null); + const [modalState, setModalState] = useState({ + isOpen: false, + mode: 'create', + event: null, + calendarUrl: '', + calendars: [], + handleSave: null, + handleDelete: null, + }); + const { user } = useAuth(); + + // Use the modal hook with state from adapter + const modal = useEventModal({ + calendars: modalState.calendars, + initialEvent: modalState.event, + initialCalendarUrl: modalState.calendarUrl, + onSubmit: async (event: IcsEvent, calendarUrl: string) => { + if (modalState.handleSave) { + await modalState.handleSave({ calendarUrl, event }); + setModalState(prev => ({ ...prev, isOpen: false })); + } + }, + onDelete: async (event: IcsEvent, calendarUrl: string) => { + if (modalState.handleDelete) { + await modalState.handleDelete({ calendarUrl, event }); + setModalState(prev => ({ ...prev, isOpen: false })); + } + }, + }); + + // Sync modal state with adapter state + useEffect(() => { + if (modalState.isOpen) { + // Always call open to update all state (event, mode, calendarUrl, calendars) + modal.open(modalState.event, modalState.mode, modalState.calendarUrl, modalState.calendars); + } else if (modal.isOpen) { + modal.close(); + } + }, [modalState.isOpen, modalState.event, modalState.mode, modalState.calendarUrl, modalState.calendars]); + + useEffect(() => { + const initCalendar = async () => { + if (!containerRef.current || !user) return; + + try { + setIsLoading(true); + setError(null); + + // Dynamically import open-calendar to avoid SSR issues (uses browser-only globals) + const { createCalendar } = await import("open-dav-calendar"); + + // Clear previous calendar instance + if (containerRef.current) { + containerRef.current.innerHTML = ""; + } + + // CalDAV server URL - proxied through Django backend + // The proxy handles authentication via session cookies + // open-calendar will discover calendars from this URL + const caldavServerUrl = `${process.env.NEXT_PUBLIC_API_ORIGIN}/api/v1.0/caldav/`; + + // Create calendar with CalDAV source + // Use fetchOptions with credentials to include cookies + const calendar = await createCalendar( + [ + { + serverUrl: caldavServerUrl, + fetchOptions: { + credentials: "include" as RequestCredentials, + headers: { + "Content-Type": "application/xml", + }, + }, + }, + ], + [], // No address books for now + containerRef.current, + { + view: "timeGridWeek", + views: ["dayGridMonth", "timeGridWeek", "timeGridDay", "listWeek"], + locale: "fr", + date: selectedDate, + editable: true, + // Use custom EventEditHandlers that update React state + ...createEventModalHandlers(setModalState, []), + onEventCreated: (info) => { + console.log("Event created:", info); + }, + onEventUpdated: (info) => { + console.log("Event updated:", info); + }, + onEventDeleted: (info) => { + console.log("Event deleted:", info); + }, + }, + { + // French translations + calendar: { + today: "Aujourd'hui", + month: "Mois", + week: "Semaine", + day: "Jour", + list: "Liste", + }, + event: { + edit: "Modifier", + delete: "Supprimer", + save: "Enregistrer", + cancel: "Annuler", + title: "Titre", + description: "Description", + location: "Lieu", + startDate: "Date de début", + endDate: "Date de fin", + allDay: "Journée entière", + }, + } + ); + + calendarRef.current = calendar; + setIsLoading(false); + } catch (err) { + console.error("Failed to initialize calendar:", err); + setError( + err instanceof Error + ? err.message + : "Erreur lors du chargement du calendrier" + ); + setIsLoading(false); + } + }; + + initCalendar(); + + return () => { + // Cleanup + if (containerRef.current) { + containerRef.current.innerHTML = ""; + } + calendarRef.current = null; + }; + }, [user]); + + // Update calendar date when selectedDate changes + useEffect(() => { + if (calendarRef.current && selectedDate) { + // open-calendar may have a method to set date + // This depends on the CalendarElement API + } + }, [selectedDate]); + + if (!user) { + return ( +
+

Connexion requise pour afficher le calendrier

+
+ ); + } + + if (error) { + return ( +
+

{error}

+ +
+ ); + } + + return ( +
+ {isLoading && ( +
+

Chargement du calendrier...

+
+ )} +
+ {modal.Modal} +
+ ); +}; diff --git a/src/frontend/apps/calendars/src/features/calendar/components/CreateCalendarModal.tsx b/src/frontend/apps/calendars/src/features/calendar/components/CreateCalendarModal.tsx new file mode 100644 index 0000000..04c2b8c --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/CreateCalendarModal.tsx @@ -0,0 +1,112 @@ +/** + * Modal component for creating a new calendar. + */ + +import { useState, useEffect } from "react"; +import { + Button, + Input, + Modal, + ModalSize, + useModal, +} from "@openfun/cunningham-react"; +import { useTranslation } from "next-i18next"; +import { useCreateCalendar } from "../hooks/useCalendars"; +import { addToast, ToasterItem } from "@/features/ui/components/toaster/Toaster"; +import { errorToString } from "@/features/api/APIError"; + +export const useCreateCalendarModal = () => { + const { t } = useTranslation(); + const modal = useModal(); + const createCalendar = useCreateCalendar(); + const [name, setName] = useState(""); + const [isSubmitting, setIsSubmitting] = useState(false); + + // Reset form when modal opens + useEffect(() => { + if (modal.isOpen) { + setName(""); + setIsSubmitting(false); + } + }, [modal.isOpen]); + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault(); + + if (!name.trim()) { + return; + } + + setIsSubmitting(true); + try { + await createCalendar.mutateAsync({ + name: name.trim(), + }); + addToast( + + {t("calendar.created_success", { name: name.trim(), defaultValue: `Calendrier "${name.trim()}" créé avec succès` })} + + ); + setName(""); + modal.close(); + } catch (error) { + console.error("Failed to create calendar:", error); + const errorMessage = errorToString(error); + addToast( + + {errorMessage || t("calendar.created_error", { defaultValue: "Erreur lors de la création du calendrier" })} + + ); + } finally { + setIsSubmitting(false); + } + }; + + const handleClose = () => { + setName(""); + modal.close(); + }; + + return { + ...modal, + Modal: ( + +
+ ) => setName(e.target.value)} + required + disabled={isSubmitting} + autoFocus + placeholder={t("calendar.create_modal.name_placeholder", { defaultValue: "Mon calendrier" })} + /> +
+ + +
+
+
+ ), + }; +}; diff --git a/src/frontend/apps/calendars/src/features/calendar/components/EventModal.scss b/src/frontend/apps/calendars/src/features/calendar/components/EventModal.scss new file mode 100644 index 0000000..381a78b --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/EventModal.scss @@ -0,0 +1,90 @@ +.event-modal { + &__feature-tag { + display: inline-flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 1rem; + border-radius: 2rem; + border: none; + background: #f1f3f4; + color: #5f6368; + cursor: pointer; + font-size: 0.875rem; + transition: background-color 0.15s, color 0.15s; + + &:hover { + background: #e8eaeb; + } + + &--active { + background: #e8f0fe; + color: #1a73e8; + + &:hover { + background: #d2e3fc; + } + } + + .material-icons { + font-size: 1.125rem; + } + } +} + +// Utility classes for layout +.event-modal-layout { + display: flex; + flex-direction: column; + + &--row { + flex-direction: row; + } + + &--wrap { + flex-wrap: wrap; + } + + &--justify-space-between { + justify-content: space-between; + } + + &--align-center { + align-items: center; + } + + &--flex-1 { + flex: 1; + } + + &--gap-2rem { + gap: 2rem; + } + + &--gap-1rem { + gap: 1rem; + } + + &--gap-0-5rem { + gap: 0.5rem; + } + + &--margin-bottom-1rem { + margin-bottom: 1rem; + } + + &--margin-top-2rem { + margin-top: 2rem; + } + + &--margin-left-auto { + margin-left: auto; + } + + &--margin-left-2rem { + margin-left: 2rem; + } + + &--margin-top-0-5rem { + margin-top: 0.5rem; + } +} diff --git a/src/frontend/apps/calendars/src/features/calendar/components/EventModal.tsx b/src/frontend/apps/calendars/src/features/calendar/components/EventModal.tsx new file mode 100644 index 0000000..cc904f6 --- /dev/null +++ b/src/frontend/apps/calendars/src/features/calendar/components/EventModal.tsx @@ -0,0 +1,441 @@ +import { Modal, Button, Input, TextArea, Select } from '@openfun/cunningham-react'; +import type { IcsEvent, IcsRecurrenceRule } from 'ts-ics'; +import { useState, useEffect, useRef } from "react"; +import { RecurrenceEditor } from './RecurrenceEditor'; + +// Helper function to check if event is all-day (same logic as open-dav-calendar) +function isEventAllDay(event: IcsEvent): boolean { + return event.start.type === 'DATE' || (event.end?.type === 'DATE'); +} + +// Calendar type from open-calendar (exported for use in other components) +export interface Calendar { + url: string; + uid?: unknown; + displayName?: string; + calendarColor?: string; + description?: string; +} + +interface EventModalProps { + isOpen: boolean; + mode: 'create' | 'edit'; + calendars: Calendar[]; + selectedEvent?: IcsEvent | null; + calendarUrl: string; + onSubmit: (event: IcsEvent, calendarUrl: string) => Promise; + onAllDayChange: (isAllDay: boolean) => void; + onClose: () => void; + onDelete?: (event: IcsEvent, calendarUrl: string) => Promise; +} + +const VISIBILITY_OPTIONS = [ + { value: 'default', label: 'Par défaut' }, + { value: 'public', label: 'Public' }, + { value: 'private', label: 'Privé' }, +] as const; + +export function EventModal({ + isOpen, + mode, + calendars, + selectedEvent, + calendarUrl, + onSubmit, + onAllDayChange, + onClose, + onDelete, +}: EventModalProps) { + const titleInputRef = useRef(null); + const [formData, setFormData] = useState>({}); + const [activeFeatures, setActiveFeatures] = useState>(new Set()); + const [selectedCalendarUrl, setSelectedCalendarUrl] = useState(calendarUrl); + const [allDay, setAllDay] = useState(false); + + // Helper to get local date from IcsDateObject + const getLocalDate = (dateObj: { date: Date; local?: { date: Date; timezone: string } }): Date => { + return dateObj.local?.date || dateObj.date; + }; + + // Format date for input + const formatDateForInput = (date: Date): string => { + return date.toISOString().split('T')[0]; + }; + + // Format time for input + const formatTimeForInput = (date: Date): string => { + return date.toTimeString().slice(0, 5); + }; + + useEffect(() => { + if (selectedEvent) { + const eventAllDay = isEventAllDay(selectedEvent); + const startDate = getLocalDate(selectedEvent.start); + const endDate = selectedEvent.end ? getLocalDate(selectedEvent.end) : startDate; + + setAllDay(eventAllDay); + setFormData({ + ...selectedEvent, + summary: selectedEvent.summary || '', + startTime: eventAllDay ? undefined : formatTimeForInput(startDate), + endTime: eventAllDay ? undefined : formatTimeForInput(endDate), + }); + setSelectedCalendarUrl(calendarUrl); + } else { + const now = new Date(); + const endTime = new Date(now.getTime() + 30 * 60 * 1000); + setAllDay(false); + setFormData({ + summary: '', + start: { + type: 'DATE-TIME', + date: now, + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }, + end: { + type: 'DATE-TIME', + date: endTime, + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }, + startTime: formatTimeForInput(now), + endTime: formatTimeForInput(endTime), + }); + setSelectedCalendarUrl(calendars[0]?.url || ''); + } + }, [selectedEvent, calendars, calendarUrl]); + + useEffect(() => { + if (isOpen) { + requestAnimationFrame(() => { + titleInputRef.current?.focus(); + }); + } + }, [isOpen]); + + const startDate = formData.start ? getLocalDate(formData.start) : new Date(); + const endDate = formData.end ? getLocalDate(formData.end) : startDate; + + const toggleFeature = (feature: string) => { + if (feature === 'allDay') { + const newAllDay = !allDay; + setAllDay(newAllDay); + onAllDayChange(newAllDay); + return; + } + + setActiveFeatures(prev => { + const next = new Set(prev); + if (next.has(feature)) { + next.delete(feature); + } else { + next.add(feature); + } + return next; + }); + }; + + const handleSubmit = async () => { + if (!formData.summary) return; + + const startDateValue = new Date(`${formatDateForInput(startDate)}T${allDay ? '00:00:00' : formData.startTime || '00:00:00'}`); + const endDateValue = new Date(`${formatDateForInput(endDate)}T${allDay ? '00:00:00' : formData.endTime || '00:00:00'}`); + + const updatedEvent: IcsEvent = { + ...(selectedEvent || {}), + uid: selectedEvent?.uid || `event-${Date.now()}`, + summary: formData.summary || '', + location: formData.location || undefined, + description: formData.description || formData.notes || undefined, + start: { + type: allDay ? 'DATE' : 'DATE-TIME', + date: startDateValue, + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }, + end: { + type: allDay ? 'DATE' : 'DATE-TIME', + date: endDateValue, + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }, + recurrenceRule: formData.recurrenceRule, + }; + + await onSubmit(updatedEvent, selectedCalendarUrl); + }; + + const renderFeatureContent = () => { + return ( + <> + {activeFeatures.has('calendar') && ( +
+ setFormData(prev => ({ ...prev, location: e.target.value }))} + icon={location_on} + /> +
+ )} + + {activeFeatures.has('notes') && ( +
+ +
+
+ + +
+
+ + + +
+` + +const calendarsHtml = /*html*/` + +{{#calendars}} + +{{/calendars}}` + +const mailboxesHtml = /*html*/` +{{#mailboxes}} + +{{/mailboxes}}` + +const attendeeHtml = /*html*/` +
+ + + + +
` + +export class EventEditPopup { + + private _recurringPopup: RecurringEventPopup + private _popup: Popup + private _form: HTMLFormElement + private _calendar: HTMLSelectElement + private _mailboxes: HTMLDataListElement + private _attendees: HTMLDivElement + private _rruleUnchanged: HTMLOptionElement + + private _hideVCardEmails?: boolean + private _vCardContacts: VCard[] = [] + private _eventContacts: Contact[] = [] + + private _event?: IcsEvent + private _userContact?: Contact + private _calendarUrl?: string + private _handleSave: EventEditCallback | null = null + private _handleDelete: EventEditCallback | null = null + + public constructor(target: Node, options: DefaultComponentsOptions) { + this._hideVCardEmails = options.hideVCardEmails + const timezones = tzlib_get_timezones() as string[] + + this._recurringPopup = new RecurringEventPopup(target) + + this._popup = new Popup(target) + this._form = parseHtml(html, { + t: getTranslations().eventForm, + trrules: getTranslations().rrules, + timezones: timezones, + rrules: namedRRules.map(rule => ({ rule, label: getTranslations().rrules[rule] })), + userParticipationStatuses: attendeeUserParticipationStatusTypes.map(stat => ({ + key: stat, + translation: getTranslations().userParticipationStatus[stat], + })), + })[0] + this._popup.content.appendChild(this._form) + + this._calendar = this._form.querySelector('.open-calendar__form__content [name="calendar"]')! + this._mailboxes = this._form.querySelector('#open-calendar__event-edit__mailboxes')! + this._attendees = this._form.querySelector( + '.open-calendar__event-edit__attendees > .open-calendar__form__list', + )! + const allday = this._form.querySelector('.open-calendar__event-edit [name="allday"]')! + const addAttendee = this._form.querySelector('.open-calendar__event-edit__attendees > button')! + this._rruleUnchanged = this._form.querySelector('.open-calendar__event-edit__rrule__unchanged')! + const cancel = this._form.querySelector('.open-calendar__form__buttons [name="cancel"]')! + const remove = this._form.querySelector('.open-calendar__form__buttons [name="delete"]')! + + this._form.addEventListener('submit', async (e) => { e.preventDefault(); await this.save() }) + allday.addEventListener('click', this.updateAllday) + addAttendee.addEventListener('click', () => this.addAttendee({ email: '' })) + cancel.addEventListener('click', this.cancel) + remove.addEventListener('click', this.delete) + } + + public destroy = () => { + this._form.remove() + } + + private setCalendars = (calendars: Calendar[]) => { + const calendarElements = parseHtml(calendarsHtml, { + calendars, + t: getTranslations().eventForm, + }) + this._calendar.innerHTML = '' + this._calendar.append(...Array.from(calendarElements)) + } + + private setContacts = (vCardContacts: VCard[], eventContacts: Contact[]) => { + this._vCardContacts = [] + for (const contact of vCardContacts) { + if (this._vCardContacts.find(c => isSameContact(c, contact))) continue + this._vCardContacts.push(contact) + } + for (const contact of eventContacts) { + if (this._vCardContacts.find(c => isSameContact(c, contact))) continue + if (this._eventContacts.find(c => isSameContact(c, contact))) continue + this._eventContacts.push(contact) + } + const mailboxesElement = parseHtml(mailboxesHtml, { + mailboxes: [ + ...this._vCardContacts.map(c => this.getValueFromVCard(c)), + ...this._eventContacts.map(c => this.getValueFromContact(c)), + ], + }) + this._mailboxes.innerHTML = '' + this._mailboxes.append(...Array.from(mailboxesElement)) + } + + private updateAllday = (e: DomEvent) => { + this._form.classList.toggle('open-calendar__event-edit--is-allday', (e.target as HTMLInputElement).checked) + } + + private addAttendee = (attendee: IcsAttendee) => { + const element = parseHtml(attendeeHtml, { + mailbox: this.getValueFromAttendee(attendee), + role: attendee.role || 'REQ-PARTICIPANT', + roles: attendeeRoleTypes.map(role => ({ key: role, translation: getTranslations().attendeeRoles[role] })), + participationStatus: attendee.partstat || 'NEEDS-ACTION', + participationStatuses: attendeePartStatusTypes.map(status => ({ + key: status, + translation: getTranslations().participationStatus[status], + })), + t: getTranslations().eventForm, + })[0] + this._attendees.appendChild(element) + + const remove = element.querySelector('button')! + const role = element.querySelector('select[name="attendee-role"]')! + const participationStatus = element.querySelector('select[name="participation-status"]')! + + remove.addEventListener('click', () => element.remove()) + role.value = attendee.role || 'REQ-PARTICIPANT' + participationStatus.value = attendee.partstat || 'NEEDS-ACTION' + } + + public onCreate = ({calendars, vCards, event, handleCreate, userContact}: EventEditCreateInfo) => { + this._form.classList.toggle('open-calendar__event-edit--create', true) + this._handleSave = handleCreate + this._handleDelete = null + this.open('', event, calendars, vCards, userContact) + } + public onSelect = ({ + calendarUrl, + calendars, + vCards, + event, + recurringEvent, + handleDelete, + handleUpdate, + userContact, + }: EventEditSelectInfo) => { + this._form.classList.toggle('open-calendar__event-edit--create', false) + this._handleSave = handleUpdate + this._handleDelete = handleDelete + if (!recurringEvent) this.open(calendarUrl, event, calendars, vCards, userContact) + else this._recurringPopup.open(editAll => { + return this.open( + calendarUrl, editAll ? recurringEvent : event, calendars, vCards, userContact) + }) + } + + public onMoveResize = ({ calendarUrl, event, start, end, handleUpdate }: EventEditMoveResizeInfo) => { + const newEvent = { ...event } + const startDelta = start.getTime() - event.start.date.getTime() + newEvent.start = offsetDate(newEvent.start, startDelta) + if (event.end) { + const endDelta = end.getTime() - event.end.date.getTime() + newEvent.end = offsetDate(event.end, endDelta) + } + handleUpdate( + { calendarUrl, event: newEvent } as CalendarEvent, + ) + } + + public onDelete = ({ calendarUrl, event, handleDelete}: EventEditDeleteInfo) => { + handleDelete({calendarUrl, event}) + } + + public open = ( + calendarUrl: string, + event: IcsEvent, + calendars: Calendar[], + vCards: AddressBookVCard[], + userContact?: Contact, + ) => { + this._userContact = userContact + this.setContacts( + vCards.filter(c => c.vCard.email !== null).map(c => c.vCard), + [...event.attendees ?? [], event.organizer].filter(a => a !== undefined), + ) + this.setCalendars(calendars) + + this._calendarUrl = calendarUrl + this._event = event + const localTzId = Intl.DateTimeFormat().resolvedOptions().timeZone + const localTzOffset = new Date().getTimezoneOffset() * TIME_MINUTE + const localStart = event.start.local ?? { + date: new Date(event.start.date.getTime() - localTzOffset), + timezone: localTzId, + } + const end = event.end ?? + offsetDate( + localStart, + getEventEndFromDuration(event.start.date, event.duration).getTime() - event.start.date.getTime(), + ) + const localEnd = end.local ?? { + date: new Date(end.date.getTime() - localTzOffset), + timezone: localTzId, + } + + const inputs = this._form.elements; + (inputs.namedItem('calendar') as HTMLInputElement).value = calendarUrl; + (inputs.namedItem('calendar') as HTMLInputElement).disabled = event.recurrenceId !== undefined; + // FIXME - CJ - 2025/06/03 - changing an object of calendar is not supported; + (inputs.namedItem('calendar') as HTMLInputElement).disabled ||= + !this._form.classList.contains('open-calendar__event-edit--create'); + (inputs.namedItem('summary') as HTMLInputElement).value = event.summary ?? ''; + (inputs.namedItem('location') as HTMLInputElement).value = event.location ?? ''; + (inputs.namedItem('allday') as HTMLInputElement).checked = isEventAllDay(event) + this._form.classList.toggle('open-calendar__event-edit--is-allday', isEventAllDay(event)) + const startDateTime = localStart.date.toISOString().split('T'); + (inputs.namedItem('start-date') as HTMLInputElement).value = startDateTime[0]; + (inputs.namedItem('start-time') as HTMLInputElement).value = startDateTime[1].slice(0, 5); + (inputs.namedItem('start-timezone') as HTMLInputElement).value = localStart.timezone + const endDateTime = localEnd.date.toISOString().split('T'); + (inputs.namedItem('end-date') as HTMLInputElement).value = endDateTime[0]; + (inputs.namedItem('end-time') as HTMLInputElement).value = endDateTime[1].slice(0, 5); + (inputs.namedItem('end-timezone') as HTMLInputElement).value = localEnd.timezone; + // TODO - CJ - 2025-07-03 - Add rich text support + (inputs.namedItem('description') as HTMLInputElement).value = event.description ?? ''; + + // TODO - CJ - 2025-07-03 - Check if needs to be hidden or done differently, + // as I believe Thunderbird also adds the organizer to the attendee list; + (inputs.namedItem('organizer-mailbox') as HTMLInputElement).value = event.organizer + ? this.getValueFromAttendee(event.organizer) + : '' + + const rrule = getRRuleString(event.recurrenceRule) + this._rruleUnchanged.value = rrule; + (inputs.namedItem('rrule') as HTMLInputElement).value = rrule; + (inputs.namedItem('rrule') as HTMLInputElement).disabled = event.recurrenceId !== undefined + + const userAttendeeInEvent = userContact !== undefined + ? event.attendees?.find(a => a.email === userContact.email) + : undefined + + if (userAttendeeInEvent !== undefined) { + this._form.classList.remove('open-calendar__event-edit--without-invite'); + (inputs.namedItem('user-participation-status') as HTMLSelectElement).value = + userAttendeeInEvent.partstat + ?? attendeeUserParticipationStatusTypes[0] + } else { + this._form.classList.add('open-calendar__event-edit--without-invite') + } + + + this._attendees.innerHTML = '' + for (const attendee of event.attendees ?? []) this.addAttendee(attendee) + + this._popup.setVisible(true) + } + + public save = async () => { + const data = new FormData(this._form) + const allDay = !!data.get('allday') + + const getTimeObject = (name: string): IcsDateObject => { + const date = data.get(`${name}-date`) as string + const time = data.get(`${name}-time`) as string + const timezone = data.get(`${name}-timezone`) as string + const offset = tzlib_get_offset(timezone, date, time) + return { + date: new Date(date + (allDay ? '' : `T${time}${offset}`)), + type: allDay ? 'DATE' : 'DATE-TIME', + local: timezone === 'UTC' ? undefined : { + date: new Date(date + (allDay ? '' : `T${time}Z`)), + timezone: tzlib_get_ical_block(timezone)[1].slice(5), + tzoffset: offset, + }, + } + } + + const mailboxes = data.getAll('attendee-mailbox') as string[] + const roles = data.getAll('attendee-role') as string[] + const participationStatuses = data.getAll('participation-status') as string[] + const rrule = data.get('rrule') as string + const description = data.get('description') as string + + const event: IcsEvent = { + ...this._event!, + summary: data.get('summary') as string, + location: data.get('location') as string || undefined, + start: getTimeObject('start'), + end: getTimeObject('end'), + description: description || undefined, + descriptionAltRep: description === this._event!.description ? this._event!.descriptionAltRep : undefined, + organizer: data.get('organizer-mailbox') + ? { + ...this._event!.organizer, + ...this.getContactFromValue(data.get('organizer-mailbox') as string), + } + : undefined, + attendees: mailboxes.map((mailbox, i) => { + const contact = this.getContactFromValue(mailbox) + return ({ + ...contact, + role: roles[i], + partstat: (contact.email === this._userContact?.email + ? data.get('user-participation-status') + : participationStatuses[i] + ) as IcsAttendeePartStatusType, + }) + }) || undefined, + recurrenceRule: rrule ? convertIcsRecurrenceRule(undefined, {value: rrule}) : undefined, + + // NOTE - CJ - 2025-07-03 - explicitly set `duration` to undefined as we set `end` + duration: undefined, + } + const response = await this._handleSave!({ calendarUrl: data.get('calendar') as string, event }) + if (response.ok) this._popup.setVisible(false) + } + + public cancel = () => { + this._popup.setVisible(false) + } + + public delete = async () => { + await this._handleDelete!({ calendarUrl: this._calendarUrl!, event: this._event!}) + this._popup.setVisible(false) + } + + public getContactFromValue = (value: string) => { + const contact = this._vCardContacts.find(c => this.getValueFromVCard(c) === value) + return contact + // NOTE - CJ - 2025-07-17 - we need to reconstruct an object as the spread syntax does not work for properties + ? { name: contact.name!, email: contact.email!} + : this._eventContacts.find(c => this.getValueFromContact(c) === value) + ?? mailboxToContact(value) + } + + public getValueFromAttendee = (attendee: IcsAttendee | IcsOrganizer): string => { + const vCard = this._vCardContacts.find(c => isSameContact(c, attendee)) + return vCard ? this.getValueFromVCard(vCard) : this.getValueFromContact(attendee) + } + + public getValueFromVCard = (contact: VCard) => (this._hideVCardEmails && contact.name) || contactToMailbox(contact) + public getValueFromContact = (contact: Contact) => contactToMailbox(contact) +} diff --git a/src/frontend/packages/open-calendar/src/eventeditpopup/recurringEventPopup.ts b/src/frontend/packages/open-calendar/src/eventeditpopup/recurringEventPopup.ts new file mode 100644 index 0000000..a780d37 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/eventeditpopup/recurringEventPopup.ts @@ -0,0 +1,49 @@ +import { Popup } from '../popup/popup' +import { parseHtml } from '../helpers/dom-helper' +import { getTranslations } from '../translations' + +const html = /*html*/` +
+ {{t.editRecurring}} +
+ + +
+
+` + +export class RecurringEventPopup { + + public _handleSelect?: (editAll: boolean) => void + + private _element: HTMLDivElement + private _popup: Popup + + public constructor(target: Node) { + this._popup = new Popup(target) + this._element = parseHtml(html, { t: getTranslations().recurringForm })[0] + this._popup.content.appendChild(this._element) + + const editAll = this._element.querySelector('.open-calendar__form__buttons [name="edit-all"]')! + const editSingle = this._element.querySelector( + '.open-calendar__form__buttons [name="edit-single"]', + )! + + editAll.addEventListener('click', () => this.close(true)) + editSingle.addEventListener('click', () => this.close(false)) + } + + public destroy = () => { + this._element.remove() + this._popup.destroy() + } + + public open = (handleSelect: (editAll: boolean) => void) => { + this._handleSelect = handleSelect + this._popup.setVisible(true) + } + private close = (editAll: boolean) => { + this._popup.setVisible(false) + this._handleSelect?.(editAll) + } +} diff --git a/src/frontend/packages/open-calendar/src/helpers/dav-helper.ts b/src/frontend/packages/open-calendar/src/helpers/dav-helper.ts new file mode 100644 index 0000000..ff50324 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/helpers/dav-helper.ts @@ -0,0 +1,273 @@ +import { tzlib_get_ical_block } from 'timezones-ical-library' +import { convertIcsCalendar, convertIcsTimezone, generateIcsCalendar, type IcsCalendar } from 'ts-ics' +import { createAccount, + fetchCalendars as davFetchCalendars, + fetchCalendarObjects as davFetchCalendarObjects, + createCalendarObject as davCreateCalendarObject, + updateCalendarObject as davUpdateCalendarObject, + deleteCalendarObject as davDeleteCalendarObject, + DAVNamespaceShort, + propfind, + type DAVCalendar, + type DAVCalendarObject, + type DAVAddressBook, + fetchAddressBooks as davFetchAddressBooks, + fetchVCards as davFetchVCards, +} from 'tsdav' +import { isServerSource } from './types-helper' +import type { Calendar, CalendarObject } from '../types/calendar' +import type { CalendarSource, ServerSource, CalendarResponse, AddressBookSource } from '../types/options' +import type { AddressBook, AddressBookObject } from '../types/addressbook' +import ICAL from 'ical.js' + +export function getEventObjectString(event: IcsCalendar) { + return generateIcsCalendar(event) +} + +export async function fetchCalendars(source: ServerSource | CalendarSource): Promise { + if (isServerSource(source)) { + const account = await createAccount({ + account: { serverUrl: source.serverUrl, accountType: 'caldav' }, + headers: source.headers, + fetchOptions: source.fetchOptions, + }) + const calendars = await davFetchCalendars({ account, headers: source.headers, fetchOptions: source.fetchOptions }) + return calendars.map(calendar => ({ ...calendar, headers: source.headers, fetchOptions: source.fetchOptions })) + } else { + const calendar = await davFetchCalendar({ + url: source.calendarUrl, + headers: source.headers, + fetchOptions: source.fetchOptions, + }) + return [{ ...calendar, headers: source.headers, fetchOptions: source.fetchOptions, uid: source.calendarUid }] + } +} + +export async function fetchCalendarObjects( + calendar: Calendar, + timeRange?: { start: string; end: string; }, + expand?: boolean, +): Promise<{ calendarObjects: CalendarObject[], recurringObjects: CalendarObject[] }> { + const davCalendarObjects = await davFetchCalendarObjects({ + calendar: calendar, + timeRange, expand, + headers: calendar.headers, + fetchOptions: calendar.fetchOptions, + }) + const calendarObjects = davCalendarObjects.map(o => ({ + url: o.url, + etag: o.etag, + data: convertIcsCalendar(undefined, o.data), + calendarUrl: calendar.url, + })) + const recurringObjectsUrls = new Set( + calendarObjects + .filter(c => c.data.events?.find(e => e.recurrenceId)) + .map(c => c.url), + ) + const davRecurringObjects = recurringObjectsUrls.size == 0 + ? [] + : await davFetchCalendarObjects({ + calendar: calendar, + objectUrls: Array.from(recurringObjectsUrls), + headers: calendar.headers, + fetchOptions: calendar.fetchOptions, + }) + const recurringObjects = davRecurringObjects.map(o => ({ + url: o.url, + etag: o.etag, + data: convertIcsCalendar(undefined, o.data), + calendarUrl: calendar.url, + })) + return { calendarObjects, recurringObjects } +} + +export async function createCalendarObject( + calendar: Calendar, + calendarObjectData: IcsCalendar, +): Promise { + validateTimezones(calendarObjectData) + for (const event of calendarObjectData.events ?? []) event.uid = crypto.randomUUID() + const uid = calendarObjectData.events?.[0].uid ?? crypto.randomUUID() + const iCalString = getEventObjectString(calendarObjectData) + const response = await davCreateCalendarObject({ + calendar, + iCalString, + filename: `${uid}.ics`, + headers: calendar.headers, + fetchOptions: calendar.fetchOptions, + }) + return { response, ical: iCalString } +} + +export async function updateCalendarObject( + calendar: Calendar, + calendarObject: CalendarObject, +): Promise { + validateTimezones(calendarObject.data) + const davCalendarObject: DAVCalendarObject = { + url: calendarObject.url, + etag: calendarObject.etag, + data: getEventObjectString(calendarObject.data), + } + const response = await davUpdateCalendarObject({ + calendarObject: davCalendarObject, + headers: calendar.headers, + fetchOptions: calendar.fetchOptions, + }) + return { response, ical: davCalendarObject.data } +} + +export async function deleteCalendarObject( + calendar: Calendar, + calendarObject: CalendarObject, +): Promise { + validateTimezones(calendarObject.data) + const davCalendarObject: DAVCalendarObject = { + url: calendarObject.url, + etag: calendarObject.etag, + data: getEventObjectString(calendarObject.data), + } + const response = await davDeleteCalendarObject({ + calendarObject: davCalendarObject, + headers: calendar.headers, + fetchOptions: calendar.fetchOptions, + }) + return { response, ical: davCalendarObject.data } + +} + +function validateTimezones(calendarObjectData: IcsCalendar) { + const calendar = calendarObjectData + const usedTimezones = calendar.events?.flatMap(e => [e.start.local?.timezone, e.end?.local?.timezone]) + const wantedTzIds = new Set(usedTimezones?.filter(s => s !== undefined)) + calendar.timezones ??= [] + + // Remove extra timezones + calendar.timezones = calendar.timezones.filter(tz => wantedTzIds.has(tz.id)) + + // Add missing timezones + wantedTzIds.forEach(tzid => { + if (calendar.timezones!.findIndex(t => t.id === tzid) === -1) { + calendar.timezones!.push(convertIcsTimezone(undefined, tzlib_get_ical_block(tzid)[0])) + } + }) +} + +// NOTE - CJ - 2025/07/03 - Inspired from https://github.com/natelindev/tsdav/blob/master/src/calendar.ts, fetchCalendars +async function davFetchCalendar(params: { + url: string, + headers?: Record, + fetchOptions?: RequestInit +}): Promise { + const { url, headers, fetchOptions } = params + const response = await propfind({ + url, + props: { + [`${DAVNamespaceShort.CALDAV}:calendar-description`]: {}, + [`${DAVNamespaceShort.CALDAV}:calendar-timezone`]: {}, + [`${DAVNamespaceShort.DAV}:displayname`]: {}, + [`${DAVNamespaceShort.CALDAV_APPLE}:calendar-color`]: {}, + [`${DAVNamespaceShort.CALENDAR_SERVER}:getctag`]: {}, + [`${DAVNamespaceShort.DAV}:resourcetype`]: {}, + [`${DAVNamespaceShort.CALDAV}:supported-calendar-component-set`]: {}, + [`${DAVNamespaceShort.DAV}:sync-token`]: {}, + }, + headers, + fetchOptions, + }) + const rs = response[0] + if (!rs.ok) { + throw new Error(`Calendar ${url} does not exists. ${rs.status} ${rs.statusText}`) + } + if (Object.keys(rs.props?.resourceType ?? {}).includes('calendar')) { + throw new Error(`${url} is not a ${rs.props?.resourceType} and not a calendar`) + } + const description = rs.props?.calendarDescription + const timezone = rs.props?.calendarTimezone + return { + description: typeof description === 'string' ? description : '', + timezone: typeof timezone === 'string' ? timezone : '', + url: params.url, + ctag: rs.props?.getctag, + calendarColor: rs.props?.calendarColor, + displayName: rs.props?.displayname._cdata ?? rs.props?.displayname, + components: Array.isArray(rs.props?.supportedCalendarComponentSet.comp) + // NOTE - CJ - 2025-07-03 - comp represents an list of XML nodes in the DAVResponse format + // sc could be `` + // eslint-disable-next-line @typescript-eslint/no-explicit-any + ? rs.props?.supportedCalendarComponentSet.comp.map((sc: any) => sc._attributes.name) + : [rs.props?.supportedCalendarComponentSet.comp?._attributes.name], + resourcetype: Object.keys(rs.props?.resourcetype), + syncToken: rs.props?.syncToken, + } +} + +export async function fetchAddressBooks(source: ServerSource | AddressBookSource): Promise { + if (isServerSource(source)) { + const account = await createAccount({ + account: { serverUrl: source.serverUrl, accountType: 'caldav' }, + headers: source.headers, + fetchOptions: source.fetchOptions, + }) + const books = await davFetchAddressBooks({ account, headers: source.headers, fetchOptions: source.fetchOptions }) + return books.map(book => ({ ...book, headers: source.headers, fetchOptions: source.fetchOptions })) + } else { + const book = await davFetchAddressBook({ + url: source.addressBookUrl, + headers: source.headers, + fetchOptions: source.fetchOptions, + }) + return [{ ...book, headers: source.headers, fetchOptions: source.fetchOptions, uid: source.addressBookUid }] + } +} + + +// NOTE - CJ - 2025/07/03 - Inspired from https://github.com/natelindev/tsdav/blob/master/src/addressBook.ts#L73 +async function davFetchAddressBook(params: { + url: string, + headers?: Record, + fetchOptions?: RequestInit +}): Promise { + const { url, headers, fetchOptions } = params + const response = await propfind({ + url, + props: { + [`${DAVNamespaceShort.DAV}:displayname`]: {}, + [`${DAVNamespaceShort.CALENDAR_SERVER}:getctag`]: {}, + [`${DAVNamespaceShort.DAV}:resourcetype`]: {}, + [`${DAVNamespaceShort.DAV}:sync-token`]: {}, + }, + headers, + fetchOptions, + }) + const rs = response[0] + if (!rs.ok) { + throw new Error(`Address book ${url} does not exists. ${rs.status} ${rs.statusText}`) + } + if (Object.keys(rs.props?.resourceType ?? {}).includes('addressbook')) { + throw new Error(`${url} is not a ${rs.props?.resourceType} and not an addressbook`) + } + const displayName = rs.props?.displayname?._cdata ?? rs.props?.displayname + return { + url: url, + ctag: rs.props?.getctag, + displayName: typeof displayName === 'string' ? displayName : '', + resourcetype: Object.keys(rs.props?.resourcetype), + syncToken: rs.props?.syncToken, + } +} + +export async function fetchAddressBookObjects(addressBook: AddressBook): Promise { + const davVCards = await davFetchVCards({ + addressBook: addressBook, + headers: addressBook.headers, + fetchOptions: addressBook.fetchOptions, + }) + return davVCards.map(o => ({ + url: o.url, + etag: o.etag, + data: new ICAL.Component(ICAL.parse(o.data)), + addressBookUrl: addressBook.url, + })) +} diff --git a/src/frontend/packages/open-calendar/src/helpers/dom-helper.ts b/src/frontend/packages/open-calendar/src/helpers/dom-helper.ts new file mode 100644 index 0000000..82c8c6f --- /dev/null +++ b/src/frontend/packages/open-calendar/src/helpers/dom-helper.ts @@ -0,0 +1,11 @@ +import Mustache from 'mustache' + +export function parseHtml(html: string, format?: unknown): NodeListOf { + html = Mustache.render(html, format) + return Document.parseHTMLUnsafe(html).body.childNodes as NodeListOf +} + +export function escapeHtml(html: string): string { + // NOTE - CJ - 2025-07-07 - In Mustache, {{html}} escapes html whereas {{{html}}} and {{&html}} do not + return Mustache.render('{{html}}', { html }) +} diff --git a/src/frontend/packages/open-calendar/src/helpers/ics-helper.ts b/src/frontend/packages/open-calendar/src/helpers/ics-helper.ts new file mode 100644 index 0000000..c3f3930 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/helpers/ics-helper.ts @@ -0,0 +1,56 @@ +import { generateIcsRecurrenceRule, type IcsDateObject, type IcsEvent, type IcsRecurrenceRule } from 'ts-ics' +import { parseOneAddress } from 'email-addresses' +import type { EventUid } from '../types/calendar' +import type { Contact, VCard } from '../types/addressbook' + +export function isEventAllDay(event: IcsEvent) { + return event.start.type === 'DATE' || event.end?.type === 'DATE' +} + +export function offsetDate(date: IcsDateObject, offset: number): IcsDateObject { + return { + type: date.type, + date: new Date(date.date.getTime() + offset), + local: date.local && { + date: new Date(date.local.date.getTime() + offset), + timezone: date.local.timezone, + tzoffset: date.local.tzoffset, + }, + } +} + +export function isSameEvent(a: EventUid, b: EventUid) { + return a.uid === b.uid && a.recurrenceId?.value.date.getTime() === b.recurrenceId?.value.date.getTime() +} + +export function isRRuleSourceEvent(eventInstance: EventUid, event: EventUid) { + return eventInstance.uid === event.uid && event.recurrenceId === undefined +} + +export function getRRuleString(recurrenceRule?: IcsRecurrenceRule) { + if (!recurrenceRule) return '' + return generateIcsRecurrenceRule(recurrenceRule).trim().slice(6) +} + +// FIXME - CJ - 2025-07-11 - This function should only be used for display purposes +// It does not handle escape characters properly (quotes, comments) +// and parsing the result back to a contact with `mailboxToContact` may fail +// See https://datatracker.ietf.org/doc/html/rfc5322#section-3.4 the specs +export function contactToMailbox(contact: Contact | VCard): string { + return contact.name + ? `${contact.name} <${contact.email}>` + : contact.email! +} + +export function mailboxToContact(mailbox: string): Contact { + const parsed = parseOneAddress(mailbox) + if (parsed?.type !== 'mailbox') throw new Error(`Failed to parse mailbox '${mailbox}' `) + return { + name: parsed.name ?? undefined, + email: parsed.address, + } +} + +export function isSameContact(a: Contact | VCard, b: Contact | VCard) { + return a.name === b.name && a.email === b.email +} diff --git a/src/frontend/packages/open-calendar/src/helpers/types-helper.ts b/src/frontend/packages/open-calendar/src/helpers/types-helper.ts new file mode 100644 index 0000000..0b84d5f --- /dev/null +++ b/src/frontend/packages/open-calendar/src/helpers/types-helper.ts @@ -0,0 +1,22 @@ +import type { CalendarOptions, + SelectCalendarHandlers, + EventEditHandlers, + ServerSource, + VCardProvider, +} from '../types/options' + +export function isServerSource(source: ServerSource | unknown): source is ServerSource { + return (source as ServerSource).serverUrl !== undefined +} + +export function isVCardProvider(source: VCardProvider | unknown): source is VCardProvider { + return (source as VCardProvider).fetchContacts !== undefined +} + +export function hasEventHandlers(options: CalendarOptions): options is EventEditHandlers { + return (options as EventEditHandlers).onCreateEvent !== undefined +} + +export function hasCalendarHandlers(options: CalendarOptions): options is SelectCalendarHandlers { + return (options as SelectCalendarHandlers).onClickSelectCalendars !== undefined +} diff --git a/src/frontend/packages/open-calendar/src/index.css b/src/frontend/packages/open-calendar/src/index.css new file mode 100644 index 0000000..7df3d19 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/index.css @@ -0,0 +1,50 @@ +.open-calendar__form { + display: flex; + flex-direction: column; + gap: 1rem; +} + +.open-calendar__form__content { + display: grid; + grid-template-columns: max-content max-content; + grid-gap: 5px; + align-items: baseline; +} + +.open-calendar__form__content label { + text-align: right; +} + +/* FIXME - CJ - 2025-07-03 - replace by something else that supports localization */ +.open-calendar__form__content label::after { + content: ":"; +} + +.open-calendar__form__content input[type=checkbox] { + justify-self: left; +} + +.open-calendar__form__list { + display: flex; + flex-direction: column; + grid-gap: 0.25rem; + margin-bottom: 0.25rem; +} + +.open-calendar__form__buttons { + display: flex; + gap: 1rem; +} + +.open-calendar__form__buttons>* { + flex-grow: 1; +} + +.open-calendar { + font-family: sans-serif; + height: 100%; +} + +.ec { + height: 100%; +} \ No newline at end of file diff --git a/src/frontend/packages/open-calendar/src/index.ts b/src/frontend/packages/open-calendar/src/index.ts new file mode 100644 index 0000000..e9e5f17 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/index.ts @@ -0,0 +1,23 @@ +import { CalendarElement } from './calendarelement/calendarElement' +import './index.css' +import { setTranslations, type ResourceBundle} from './translations' +import type { AddressBookSource, + CalendarOptions, + CalendarSource, + VCardProvider, + RecursivePartial, + ServerSource, +} from './types/options' + +export async function createCalendar( + calendarSources: (ServerSource | CalendarSource)[], + addressBookSources: (ServerSource | AddressBookSource | VCardProvider)[], + target: Element, + options?: CalendarOptions, + translations?: RecursivePartial, +) { + if (translations) setTranslations(translations) + const calendar = new CalendarElement() + await calendar.create(calendarSources, addressBookSources, target, options) + return calendar +} diff --git a/src/frontend/packages/open-calendar/src/popup/popup.css b/src/frontend/packages/open-calendar/src/popup/popup.css new file mode 100644 index 0000000..18bb686 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/popup/popup.css @@ -0,0 +1,24 @@ +.open-calendar__popup__overlay { + position: fixed; + width: 100vw; + height: 100vh; + left: 0px; + top: 0px; + background-color: rgba(0, 0, 0, 0.5); + display: flex; + align-items: center; + justify-content: center; + z-index: 2000; +} + +.open-calendar__popup--hidden { + display: none; +} + +.open-calendar__popup__frame { + width: fit-content; + height: fit-content; + background-color: white; + padding: 0.5rem; + border-radius: 10px; +} \ No newline at end of file diff --git a/src/frontend/packages/open-calendar/src/popup/popup.ts b/src/frontend/packages/open-calendar/src/popup/popup.ts new file mode 100644 index 0000000..1d6a48b --- /dev/null +++ b/src/frontend/packages/open-calendar/src/popup/popup.ts @@ -0,0 +1,35 @@ +import './popup.css' +import { parseHtml } from '../helpers/dom-helper' + +const html = /*html*/` +
+
+
` + +export class Popup { + + private _node: HTMLDivElement + public content: HTMLDivElement + + constructor(target: Node) { + this._node = parseHtml(html)[0] + target.appendChild(this._node) + + this.content = this._node.firstElementChild as HTMLDivElement + + window.addEventListener('mousedown', e => { + if (this._node.classList.contains('open-calendar__popup--hidden')) return + if (e.target instanceof Element && (e.target === this.content || e.target.contains(this.content))) { + this.setVisible(false) + } + }) + } + + public destroy = () => { + this._node.remove() + } + + setVisible = (visible: boolean) => { + this._node.classList.toggle('open-calendar__popup--hidden', !visible) + } +} diff --git a/src/frontend/packages/open-calendar/src/translations.ts b/src/frontend/packages/open-calendar/src/translations.ts new file mode 100644 index 0000000..243774f --- /dev/null +++ b/src/frontend/packages/open-calendar/src/translations.ts @@ -0,0 +1,123 @@ +import type { RecursivePartial } from './types/options' + +// HACK - CJ - 2025-07-03 - Ideally, this object would have been a json file and imported with: +// `import en from 'locale/en/translation.json'` +// However, the lib used to create the declarations file `index.d.ts` thinks this is ts import +// and looks for the file `locale/en/translation.json.d.ts` which doesn't exists. +const en = { + 'calendarElement': { + 'timeGridDay': 'Day', + 'timeGridWeek': 'Week', + 'dayGridMonth': 'Month', + 'listDay': 'List', + 'listWeek': 'List Week', + 'listMonth': 'List Month', + 'listYear': 'List Year', + 'today': 'Today', + 'allDay': 'Daily', + 'calendars': 'Calendars', + 'newEvent': 'New Event', + }, + 'eventForm': { + 'allDay': 'Daily', + 'calendar': 'Calendar', + 'title': 'Title', + 'location': 'Location', + 'start': 'Start', + 'end': 'End', + 'organizer': 'Organizer', + 'attendees': 'Attendees', + 'addAttendee': 'Add attendee', + 'description': 'Description', + 'delete': 'Delete', + 'cancel': 'Cancel', + 'save': 'Save', + 'chooseACalendar': '-- Choose a calendar --', + 'rrule': 'Frequency', + 'userInvite': 'You were invited to this event', + }, + 'eventBody': { + 'organizer': 'Organizer', + 'participation_require': 'Required participant', + 'participation_optional': 'Optional participant', + 'non_participant': 'Non participant', + 'participation_confirmed': 'Participation confirmed', + 'participation_pending': 'Participation pending', + 'participation_confirmed_tentative': 'Participation confirmed tentative', + 'participation_declined': 'Participation declined', + }, + 'recurringForm': { + 'editRecurring': 'This is a recurring event', + 'editAll': 'Edit all occurrences', + 'editSingle': 'Edit this occurrence only', + }, + 'participationStatus': { + 'NEEDS-ACTION': 'Needs to answer', + 'ACCEPTED': 'Accepted', + 'DECLINED': 'Declined', + 'TENTATIVE': 'Tentatively accepted', + 'DELEGATED': 'Delegated', + }, + 'userParticipationStatus': { + 'NEEDS-ACTION': 'Not answered', + 'ACCEPTED': 'Accept', + 'DECLINED': 'Decline', + 'TENTATIVE': 'Accept tentatively', + }, + 'attendeeRoles': { + 'CHAIR': 'Chair', + 'REQ-PARTICIPANT': 'Required participant', + 'OPT-PARTICIPANT': 'Optional participant', + 'NON-PARTICIPANT': 'Non participant', + }, + 'rrules': { + 'none': 'Never', + 'unchanged': 'Keep existing', + 'FREQ=DAILY': 'Daily', + 'FREQ=WEEKLY': 'Weekly', + 'BYDAY=MO,TU,WE,TH,FR;FREQ=DAILY': 'Workdays', + 'INTERVAL=2;FREQ=WEEKLY': 'Every two week', + 'FREQ=MONTHLY': 'Monthly', + 'FREQ=YEARLY': 'Yearly', + }, +} + +export type ResourceBundle = typeof en + +let translations = en + +export const setTranslations = (bundle: RecursivePartial) => translations = { + calendarElement: { + ...en.calendarElement, + ...bundle.calendarElement, + }, + eventForm: { + ...en.eventForm, + ...bundle.eventForm, + }, + eventBody: { + ...en.eventBody, + ...bundle.eventBody, + }, + recurringForm: { + ...en.recurringForm, + ...bundle.recurringForm, + }, + userParticipationStatus: { + ...en.userParticipationStatus, + ...bundle.userParticipationStatus, + }, + participationStatus: { + ...en.participationStatus, + ...bundle.participationStatus, + }, + attendeeRoles: { + ...en.attendeeRoles, + ...bundle.attendeeRoles, + }, + rrules: { + ...en.rrules, + ...bundle.rrules, + }, +} +export const getTranslations = () => translations diff --git a/src/frontend/packages/open-calendar/src/types/addressbook.ts b/src/frontend/packages/open-calendar/src/types/addressbook.ts new file mode 100644 index 0000000..d98f79c --- /dev/null +++ b/src/frontend/packages/open-calendar/src/types/addressbook.ts @@ -0,0 +1,30 @@ +import type { DAVAddressBook } from 'tsdav' +import ICAL from 'ical.js' + +export type AddressBook = DAVAddressBook & { + headers?: Record + uid?: unknown +} + +export type AddressBookObject = { + data: ICAL.Component + etag?: string + url: string + addressBookUrl: string +} + +export type VCard = { + name: string + email: string | null +} + +export type AddressBookVCard = { + // INFO - 2025-07-24 - addressBookUrl is undefined when the contact is from a VCardProvider + addressBookUrl?: string + vCard: VCard +} + +export type Contact = { + name?: string + email: string +} diff --git a/src/frontend/packages/open-calendar/src/types/calendar.ts b/src/frontend/packages/open-calendar/src/types/calendar.ts new file mode 100644 index 0000000..dfecdb9 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/types/calendar.ts @@ -0,0 +1,39 @@ +import type { IcsCalendar, IcsEvent, IcsRecurrenceId } from 'ts-ics' +import type { DAVCalendar } from 'tsdav' + +// TODO - CJ - 2025-07-03 - add generic +// TODO - CJ - 2025-07-03 - add options to support IcsEvent custom props +export type Calendar = DAVCalendar & { + // INFO - CJ - 2025-07-03 - Useful fields from 'DAVCalendar' + // ctag?: string + // description?: string; + // displayName?: string | Record; + // calendarColor?: string + // url: string + // fetchOptions?: RequestInit + headers?: Record + uid?: unknown +} + +export type CalendarObject = { + data: IcsCalendar + etag?: string + url: string + calendarUrl: string +} + +export type CalendarEvent = { + calendarUrl: string + event: IcsEvent +} + +export type EventUid = { + uid: string + recurrenceId?: IcsRecurrenceId +} + +export type DisplayedCalendarEvent = { + calendarUrl: string + event: IcsEvent + recurringEvent?: IcsEvent +} diff --git a/src/frontend/packages/open-calendar/src/types/options.ts b/src/frontend/packages/open-calendar/src/types/options.ts new file mode 100644 index 0000000..b12c0e9 --- /dev/null +++ b/src/frontend/packages/open-calendar/src/types/options.ts @@ -0,0 +1,160 @@ +import type { IcsEvent } from 'ts-ics' +import type { Calendar, CalendarEvent } from './calendar' +import type { AddressBookVCard, Contact, VCard } from './addressbook' +import type { attendeeRoleTypes, availableViews } from '../contants' + +export type RecursivePartial = { + [P in keyof T]?: RecursivePartial +} + +export type DomEvent = GlobalEventHandlersEventMap[keyof GlobalEventHandlersEventMap] + +export type ServerSource = { + serverUrl: string + headers?: Record + fetchOptions?: RequestInit +} + +export type CalendarSource = { + calendarUrl: string + calendarUid?: unknown + headers?: Record + fetchOptions?: RequestInit +} + +export type AddressBookSource = { + addressBookUrl: string + addressBookUid?: unknown + headers?: Record + fetchOptions?: RequestInit +} + +export type VCardProvider = { + fetchContacts: () => Promise +} + +export type View = typeof availableViews[number] +export type IcsAttendeeRoleType = typeof attendeeRoleTypes[number] + + +export type SelectedCalendar = { + url: string + selected: boolean +} + +export type SelectCalendarCallback = (calendar: SelectedCalendar) => void +export type SelectCalendarsClickInfo = { + jsEvent: DomEvent + calendars: Calendar[] + selectedCalendars: Set + handleSelect: SelectCalendarCallback +} +export type SelectCalendarHandlers = { + onClickSelectCalendars: (info: SelectCalendarsClickInfo) => void, +} + + +export type EventBodyInfo = { + calendar: Calendar + vCards: AddressBookVCard[] + event: IcsEvent + view: View + userContact?: Contact +} +export type BodyHandlers = { + getEventBody: (info: EventBodyInfo) => Node[] +} + +export type EventEditCallback = (event: CalendarEvent) => Promise +export type EventEditCreateInfo = { + jsEvent: DomEvent + userContact?: Contact, + event: IcsEvent + calendars: Calendar[] + vCards: AddressBookVCard[] + handleCreate: EventEditCallback +} +export type EventEditSelectInfo = { + jsEvent: DomEvent + userContact?: Contact, + calendarUrl: string + event: IcsEvent + recurringEvent?: IcsEvent + calendars: Calendar[] + vCards: AddressBookVCard[] + handleUpdate: EventEditCallback + handleDelete: EventEditCallback +} +export type EventEditMoveResizeInfo = { + jsEvent: DomEvent + calendarUrl: string + userContact?: Contact, + event: IcsEvent + recurringEvent?: IcsEvent, + start: Date, + end: Date, + handleUpdate: EventEditCallback +} +export type EventEditDeleteInfo = { + jsEvent: DomEvent + userContact?: Contact, + calendarUrl: string + event: IcsEvent + recurringEvent?: IcsEvent + handleDelete: EventEditCallback +} +export type EventEditHandlers = { + onCreateEvent: (info: EventEditCreateInfo) => void, + onSelectEvent: (info: EventEditSelectInfo) => void, + onMoveResizeEvent: (info: EventEditMoveResizeInfo) => void, + onDeleteEvent: (info: EventEditDeleteInfo) => void, +} + +export type EventChangeInfo = { + calendarUrl: string + event: IcsEvent + ical: string +} + +export type EventChangeHandlers = { + onEventCreated?: (info: EventChangeInfo) => void + onEventUpdated?: (info: EventChangeInfo) => void + onEventDeleted?: (info: EventChangeInfo) => void +} + +export type CalendarElementOptions = { + view?: View + views?: View[] + locale?: string + date?: Date + editable?: boolean +} + +export type CalendarClientOptions = { + userContact?: Contact +} + +export type DefaultComponentsOptions = { + hideVCardEmails?: boolean +} + +export type CalendarOptions = + // NOTE - CJ - 2025-07-03 + // May define individual options or not + CalendarElementOptions + // May define individual options or not + & CalendarClientOptions + // Must define all handlers or none + & (SelectCalendarHandlers | Record) + // Must define all handlers or none + & (EventEditHandlers | Record) + // May define individual handlers or not + & EventChangeHandlers + // May define handlers or not, but they will be assigned a default value if they are not + & Partial + & DefaultComponentsOptions + +export type CalendarResponse = { + response: Response + ical: string +} diff --git a/src/frontend/packages/open-calendar/src/vite-env.d.ts b/src/frontend/packages/open-calendar/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/src/frontend/packages/open-calendar/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/src/frontend/packages/open-calendar/tsconfig.json b/src/frontend/packages/open-calendar/tsconfig.json new file mode 100644 index 0000000..781d7f4 --- /dev/null +++ b/src/frontend/packages/open-calendar/tsconfig.json @@ -0,0 +1,36 @@ +{ + "include": ["src/**/*"], + "exclude": ["node_modules", "vite.config.ts"], + "compilerOptions": { + "outDir": "./dist/", + "module": "esnext", + "target": "es2020", + "lib": ["ES2020", "DOM"], + "useDefineForClassFields": true, + "skipLibCheck": true, + "types": [], + "declaration": true, + "declarationDir": "./build/", + "esModuleInterop": true, + /* Bundler mode */ + "moduleResolution": "node", + "resolveJsonModule": true, + "verbatimModuleSyntax": true, + "moduleDetection": "force", + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noImplicitAny": true, + "erasableSyntaxOnly": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + "allowSyntheticDefaultImports": true, + /* FIXME - CJ - 2025-07-03 - Compilation worked file when I added `tsconfig-paths-webpack-plugin` but I could not find a working plugin for the .d.ts files */ + // "baseUrl": "./src", + // "paths": { + // "@helpers/*": ["./helpers/*"], + // "@calendar-types": ["./types.ts"] + // }, + }, +} \ No newline at end of file diff --git a/src/frontend/packages/open-calendar/vite.config.ts b/src/frontend/packages/open-calendar/vite.config.ts new file mode 100644 index 0000000..7826993 --- /dev/null +++ b/src/frontend/packages/open-calendar/vite.config.ts @@ -0,0 +1,23 @@ +import { defineConfig } from 'vite' +import { nodePolyfills } from 'vite-plugin-node-polyfills' +// INFO - CJ - 2025-07-03 - This plugin show tsc errors on vite dev +import pluginChecker from 'vite-plugin-checker' + +export default defineConfig({ + plugins: [ + nodePolyfills(), + pluginChecker({ typescript: true }), + ], + build: { + lib: { + entry: './src/index.ts', + name: 'CalendarClient', + fileName: 'index', + }, + }, + resolve: { + alias: { + 'node-fetch': 'axios', + }, + }, +}) diff --git a/src/frontend/packages/open-calendar/webpack.config.js b/src/frontend/packages/open-calendar/webpack.config.js new file mode 100644 index 0000000..ec63624 --- /dev/null +++ b/src/frontend/packages/open-calendar/webpack.config.js @@ -0,0 +1,43 @@ +const path = require('path') +const NodePolyfillPlugin = require('node-polyfill-webpack-plugin') +const DtsBundleWebpack = require('dts-bundle-webpack') +const isProduction = process.env.NODE_ENV === 'production' || true +const name = 'open-dav-calendar' + +module.exports = { + mode: isProduction ? 'production' : 'development', + entry: { + index: "./src/index.ts", + }, + target: 'web', + plugins: [ + new NodePolyfillPlugin(), + new DtsBundleWebpack({ + name: name, + main: path.resolve(__dirname, "build/index.d.ts"), + out: path.resolve(__dirname, "dist/index.d.ts"), + }) + ], + module: { + rules: [{ + test: /\.ts$/, + use: 'ts-loader', + exclude: /node_modules/, + }, { + test: /\.css$/, + use: ['style-loader', 'css-loader'] + }], + }, + resolve: { + extensions: ['.ts', '.js'], + }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: '[name].js', + library: { + type: 'umd', + name: name, + umdNamedDefine: true + } + } +} diff --git a/src/frontend/packages/open-calendar/yarn.lock b/src/frontend/packages/open-calendar/yarn.lock new file mode 100644 index 0000000..0393425 --- /dev/null +++ b/src/frontend/packages/open-calendar/yarn.lock @@ -0,0 +1,3636 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.3.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@discoveryjs/json-ext@^0.6.1": + version "0.6.3" + resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz#f13c7c205915eb91ae54c557f5e92bddd8be0e83" + integrity sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ== + +"@esbuild/aix-ppc64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz#4e0f91776c2b340e75558f60552195f6fad09f18" + integrity sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA== + +"@esbuild/android-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz#bc766407f1718923f6b8079c8c61bf86ac3a6a4f" + integrity sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg== + +"@esbuild/android-arm@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.5.tgz#4290d6d3407bae3883ad2cded1081a234473ce26" + integrity sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA== + +"@esbuild/android-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.5.tgz#40c11d9cbca4f2406548c8a9895d321bc3b35eff" + integrity sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw== + +"@esbuild/darwin-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz#49d8bf8b1df95f759ac81eb1d0736018006d7e34" + integrity sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ== + +"@esbuild/darwin-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz#e27a5d92a14886ef1d492fd50fc61a2d4d87e418" + integrity sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ== + +"@esbuild/freebsd-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz#97cede59d638840ca104e605cdb9f1b118ba0b1c" + integrity sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw== + +"@esbuild/freebsd-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz#71c77812042a1a8190c3d581e140d15b876b9c6f" + integrity sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw== + +"@esbuild/linux-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz#f7b7c8f97eff8ffd2e47f6c67eb5c9765f2181b8" + integrity sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg== + +"@esbuild/linux-arm@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz#2a0be71b6cd8201fa559aea45598dffabc05d911" + integrity sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw== + +"@esbuild/linux-ia32@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz#763414463cd9ea6fa1f96555d2762f9f84c61783" + integrity sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA== + +"@esbuild/linux-loong64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz#428cf2213ff786a502a52c96cf29d1fcf1eb8506" + integrity sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg== + +"@esbuild/linux-mips64el@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz#5cbcc7fd841b4cd53358afd33527cd394e325d96" + integrity sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg== + +"@esbuild/linux-ppc64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz#0d954ab39ce4f5e50f00c4f8c4fd38f976c13ad9" + integrity sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ== + +"@esbuild/linux-riscv64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz#0e7dd30730505abd8088321e8497e94b547bfb1e" + integrity sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA== + +"@esbuild/linux-s390x@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz#5669af81327a398a336d7e40e320b5bbd6e6e72d" + integrity sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ== + +"@esbuild/linux-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz#b2357dd153aa49038967ddc1ffd90c68a9d2a0d4" + integrity sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw== + +"@esbuild/netbsd-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz#53b4dfb8fe1cee93777c9e366893bd3daa6ba63d" + integrity sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw== + +"@esbuild/netbsd-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz#a0206f6314ce7dc8713b7732703d0f58de1d1e79" + integrity sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ== + +"@esbuild/openbsd-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz#2a796c87c44e8de78001d808c77d948a21ec22fd" + integrity sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw== + +"@esbuild/openbsd-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz#28d0cd8909b7fa3953af998f2b2ed34f576728f0" + integrity sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg== + +"@esbuild/sunos-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz#a28164f5b997e8247d407e36c90d3fd5ddbe0dc5" + integrity sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA== + +"@esbuild/win32-arm64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz#6eadbead38e8bd12f633a5190e45eff80e24007e" + integrity sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw== + +"@esbuild/win32-ia32@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz#bab6288005482f9ed2adb9ded7e88eba9a62cc0d" + integrity sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ== + +"@esbuild/win32-x64@0.25.5": + version "0.25.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz#7fc114af5f6563f19f73324b5d5ff36ece0803d1" + integrity sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.21.0": + version "0.21.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.0.tgz#abdbcbd16b124c638081766392a4d6b509f72636" + integrity sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.3.0": + version "0.3.0" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.3.0.tgz#3e09a90dfb87e0005c7694791e58e97077271286" + integrity sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw== + +"@eslint/core@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.12.0.tgz#5f960c3d57728be9f6c65bd84aa6aa613078798e" + integrity sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.13.0.tgz#bf02f209846d3bf996f9e8009db62df2739b458c" + integrity sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.14.0.tgz#326289380968eaf7e96f364e1e4cf8f3adf2d003" + integrity sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.15.1": + version "0.15.1" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.15.1.tgz#d530d44209cbfe2f82ef86d6ba08760196dd3b60" + integrity sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/css-tree@^3.6.1": + version "3.6.1" + resolved "https://registry.yarnpkg.com/@eslint/css-tree/-/css-tree-3.6.1.tgz#7e162e2884b4581bb74e8cfe9ff1eb42cf87fc9f" + integrity sha512-5DIsBME23tUQD5zHD+T38lC2DG4jB8x8JRa+yDncLne2TIZA0VuCpcSazOX1EC+sM/q8w24qeevXfmfsIxAeqA== + dependencies: + mdn-data "2.21.0" + source-map-js "^1.0.1" + +"@eslint/css@^0.9.0": + version "0.9.0" + resolved "https://registry.yarnpkg.com/@eslint/css/-/css-0.9.0.tgz#fc095bb0a0ec5da5c7482d6360a64ba93743575b" + integrity sha512-fq8hYnjipdzVDSU/bXqv7qlvdjDA27Nq7DhQXzlPElLlVon3lnKovIM/6HaUrq1bz7EPgRobr+vOhpeM6z0X4w== + dependencies: + "@eslint/core" "^0.14.0" + "@eslint/css-tree" "^3.6.1" + "@eslint/plugin-kit" "^0.3.1" + +"@eslint/eslintrc@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" + integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== + 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" + +"@eslint/js@9.30.0", "@eslint/js@^9.29.0": + version "9.30.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.30.0.tgz#c396fa450d5505dd9b7b8846b33f0491aebd9a2d" + integrity sha512-Wzw3wQwPvc9sHM+NjakWTcPx11mbZyiYHuwWa/QfZ7cIRX7WK54PSk7bdyXDaoaopUcMatv1zaQvOAAO8hCdww== + +"@eslint/json@^0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@eslint/json/-/json-0.12.0.tgz#7d1cb7152d01f3837703c154a5b38233f409395e" + integrity sha512-n/7dz8HFStpEe4o5eYk0tdkBdGUS/ZGb0GQCeDWN1ZmRq67HMHK4vC33b0rQlTT6xdZoX935P4vstiWVk5Ying== + dependencies: + "@eslint/core" "^0.12.0" + "@eslint/plugin-kit" "^0.2.7" + "@humanwhocodes/momoa" "^3.3.4" + natural-compare "^1.4.0" + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.2.7": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz#47488d8f8171b5d4613e833313f3ce708e3525f8" + integrity sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA== + dependencies: + "@eslint/core" "^0.13.0" + levn "^0.4.1" + +"@eslint/plugin-kit@^0.3.1": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz#32926b59bd407d58d817941e48b2a7049359b1fd" + integrity sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag== + dependencies: + "@eslint/core" "^0.15.1" + levn "^0.4.1" + +"@event-calendar/core@^4.4.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/@event-calendar/core/-/core-4.5.0.tgz#bdd770f9e118d0d44b25e503471e581b604470f9" + integrity sha512-H7z3MCmXJP7Gdzdf9cxA3rR9ANw15y8cD041twStNQ3S7PniqcH+qygvZOHp45vTxNj2HA9vOUR4Reno8AK89Q== + dependencies: + svelte "^5.34.8" + +"@fortawesome/fontawesome-common-types@6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz#7123d74b0c1e726794aed1184795dbce12186470" + integrity sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg== + +"@fortawesome/fontawesome-svg-core@^6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz#0ac6013724d5cc327c1eb81335b91300a4fce2f2" + integrity sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA== + dependencies: + "@fortawesome/fontawesome-common-types" "6.7.2" + +"@fortawesome/free-regular-svg-icons@^6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz#f1651e55e6651a15589b0569516208f9c65f96db" + integrity sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g== + dependencies: + "@fortawesome/fontawesome-common-types" "6.7.2" + +"@fortawesome/free-solid-svg-icons@^6.7.2": + version "6.7.2" + resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz#fe25883b5eb8464a82918599950d283c465b57f6" + integrity sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA== + dependencies: + "@fortawesome/fontawesome-common-types" "6.7.2" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/momoa@^3.3.4": + version "3.3.8" + resolved "https://registry.yarnpkg.com/@humanwhocodes/momoa/-/momoa-3.3.8.tgz#b00630bf689b6f758419c029e15a4be25c12179b" + integrity sha512-/3PZzor2imi/RLLcnHztkwA79txiVvW145Ve2cp5dxRcH5qOUNJPToasqLFHniTfw4B4lT7jGDdBOPXbXYlIMQ== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== + +"@isaacs/balanced-match@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" + integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ== + +"@isaacs/brace-expansion@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3" + integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA== + dependencies: + "@isaacs/balanced-match" "^4.0.1" + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + 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" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.10" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.10.tgz#1cad974c8478e644c5cbce2a4b738137bb64bd4f" + integrity sha512-HM2F4B9N4cA0RH2KQiIZOHAZqtP4xGS4IZ+SFe1SIbO4dyjf9MTY2Bo3vHYnm0hglWfXqBrzUBSa+cJfl3Xvrg== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/source-map@^0.3.3": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.8.tgz#0af4be466bcbcbc7206f69623e32b3cefe3b39cd" + integrity sha512-3EDAPd0B8X1gsQQgGHU8vyxSp2MB414z3roN67fY7nI0GV3GDthHfaWcbCfrC95tpAzA5xUvAuoO9Dxx/ywwRQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.2.tgz#4f25c8f17f28ccf70ed16e03f8fbf6d3998cb8fd" + integrity sha512-gKYheCylLIedI+CSZoDtGkFV9YEBxRRVcfCH7OfAqh4TyUyRjEE6WVE/aXDXX0p8BIe/QgLcaAoI0220KRRFgg== + +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.27" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.27.tgz#3139cfeafce3aa9918454cce8b219eee39fd7df2" + integrity sha512-VO95AxtSFMelbg3ouljAYnfvTEwSWVt/2YLf+U5Ejd8iT5mXE2Sa/1LGyvySMne2CGsepGLI7KpF3EzE3Aq9Mg== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@rollup/plugin-inject@^5.0.5": + version "5.0.5" + resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-5.0.5.tgz#616f3a73fe075765f91c5bec90176608bed277a3" + integrity sha512-2+DEJbNBoPROPkgTDNe8/1YXWcqxbN5DTjASVIOx8HS+pITXushyNiBV56RB08zuptzz8gT3YfkqriTBVycepg== + dependencies: + "@rollup/pluginutils" "^5.0.1" + estree-walker "^2.0.2" + magic-string "^0.30.3" + +"@rollup/pluginutils@^5.0.1": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.2.0.tgz#eac25ca5b0bdda4ba735ddaca5fbf26bd435f602" + integrity sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + +"@rollup/rollup-android-arm-eabi@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.1.tgz#f768e3b2b0e6b55c595d7a053652c06413713983" + integrity sha512-JAcBr1+fgqx20m7Fwe1DxPUl/hPkee6jA6Pl7n1v2EFiktAHenTaXl5aIFjUIEsfn9w3HE4gK1lEgNGMzBDs1w== + +"@rollup/rollup-android-arm64@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.1.tgz#40379fd5501cfdfd7d8f86dfa1d3ce8d3a609493" + integrity sha512-RurZetXqTu4p+G0ChbnkwBuAtwAbIwJkycw1n6GvlGlBuS4u5qlr5opix8cBAYFJgaY05TWtM+LaoFggUmbZEQ== + +"@rollup/rollup-darwin-arm64@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.1.tgz#972c227bc89fe8a38a3f0c493e1966900e4e1ff7" + integrity sha512-fM/xPesi7g2M7chk37LOnmnSTHLG/v2ggWqKj3CCA1rMA4mm5KVBT1fNoswbo1JhPuNNZrVwpTvlCVggv8A2zg== + +"@rollup/rollup-darwin-x64@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.1.tgz#96c919dcb87a5aa7dec5f7f77d90de881e578fdd" + integrity sha512-gDnWk57urJrkrHQ2WVx9TSVTH7lSlU7E3AFqiko+bgjlh78aJ88/3nycMax52VIVjIm3ObXnDL2H00e/xzoipw== + +"@rollup/rollup-freebsd-arm64@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.1.tgz#d199d8eaef830179c0c95b7a6e5455e893d1102c" + integrity sha512-wnFQmJ/zPThM5zEGcnDcCJeYJgtSLjh1d//WuHzhf6zT3Md1BvvhJnWoy+HECKu2bMxaIcfWiu3bJgx6z4g2XA== + +"@rollup/rollup-freebsd-x64@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.1.tgz#cab01f9e06ca756c1fabe87d64825ae016af4713" + integrity sha512-uBmIxoJ4493YATvU2c0upGz87f99e3wop7TJgOA/bXMFd2SvKCI7xkxY/5k50bv7J6dw1SXT4MQBQSLn8Bb/Uw== + +"@rollup/rollup-linux-arm-gnueabihf@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.1.tgz#f6f1c42036dba0e58dc2315305429beff0d02c78" + integrity sha512-n0edDmSHlXFhrlmTK7XBuwKlG5MbS7yleS1cQ9nn4kIeW+dJH+ExqNgQ0RrFRew8Y+0V/x6C5IjsHrJmiHtkxQ== + +"@rollup/rollup-linux-arm-musleabihf@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.1.tgz#1157e98e740facf858993fb51431dce3a4a96239" + integrity sha512-8WVUPy3FtAsKSpyk21kV52HCxB+me6YkbkFHATzC2Yd3yuqHwy2lbFL4alJOLXKljoRw08Zk8/xEj89cLQ/4Nw== + +"@rollup/rollup-linux-arm64-gnu@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.1.tgz#b39db73f8a4c22e7db31a4f3fd45170105f33265" + integrity sha512-yuktAOaeOgorWDeFJggjuCkMGeITfqvPgkIXhDqsfKX8J3jGyxdDZgBV/2kj/2DyPaLiX6bPdjJDTu9RB8lUPQ== + +"@rollup/rollup-linux-arm64-musl@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.1.tgz#4043398049fe4449c1485312d1ae9ad8af4056dd" + integrity sha512-W+GBM4ifET1Plw8pdVaecwUgxmiH23CfAUj32u8knq0JPFyK4weRy6H7ooxYFD19YxBulL0Ktsflg5XS7+7u9g== + +"@rollup/rollup-linux-loongarch64-gnu@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.1.tgz#855a80e7e86490da15a85dcce247dbc25265bc08" + integrity sha512-1zqnUEMWp9WrGVuVak6jWTl4fEtrVKfZY7CvcBmUUpxAJ7WcSowPSAWIKa/0o5mBL/Ij50SIf9tuirGx63Ovew== + +"@rollup/rollup-linux-powerpc64le-gnu@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.1.tgz#8cf843cb7ab1d42e1dda680937cf0a2db6d59047" + integrity sha512-Rl3JKaRu0LHIx7ExBAAnf0JcOQetQffaw34T8vLlg9b1IhzcBgaIdnvEbbsZq9uZp3uAH+JkHd20Nwn0h9zPjA== + +"@rollup/rollup-linux-riscv64-gnu@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.1.tgz#287c085472976c8711f16700326f736a527f2f38" + integrity sha512-j5akelU3snyL6K3N/iX7otLBIl347fGwmd95U5gS/7z6T4ftK288jKq3A5lcFKcx7wwzb5rgNvAg3ZbV4BqUSw== + +"@rollup/rollup-linux-riscv64-musl@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.1.tgz#095ad5e53a54ba475979f1b3226b92440c95c892" + integrity sha512-ppn5llVGgrZw7yxbIm8TTvtj1EoPgYUAbfw0uDjIOzzoqlZlZrLJ/KuiE7uf5EpTpCTrNt1EdtzF0naMm0wGYg== + +"@rollup/rollup-linux-s390x-gnu@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.1.tgz#a3dec8281d8f2aef1703e48ebc65d29fe847933c" + integrity sha512-Hu6hEdix0oxtUma99jSP7xbvjkUM/ycke/AQQ4EC5g7jNRLLIwjcNwaUy95ZKBJJwg1ZowsclNnjYqzN4zwkAw== + +"@rollup/rollup-linux-x64-gnu@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.1.tgz#4b211e6fd57edd6a134740f4f8e8ea61972ff2c5" + integrity sha512-EtnsrmZGomz9WxK1bR5079zee3+7a+AdFlghyd6VbAjgRJDbTANJ9dcPIPAi76uG05micpEL+gPGmAKYTschQw== + +"@rollup/rollup-linux-x64-musl@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.1.tgz#3ecbf8e21b4157e57bb15dc6837b6db851f9a336" + integrity sha512-iAS4p+J1az6Usn0f8xhgL4PaU878KEtutP4hqw52I4IO6AGoyOkHCxcc4bqufv1tQLdDWFx8lR9YlwxKuv3/3g== + +"@rollup/rollup-win32-arm64-msvc@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.1.tgz#d4aae38465b2ad200557b53c8c817266a3ddbfd0" + integrity sha512-NtSJVKcXwcqozOl+FwI41OH3OApDyLk3kqTJgx8+gp6On9ZEt5mYhIsKNPGuaZr3p9T6NWPKGU/03Vw4CNU9qg== + +"@rollup/rollup-win32-ia32-msvc@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.1.tgz#0258e8ca052abd48b23fd6113360fa0cd1ec3e23" + integrity sha512-JYA3qvCOLXSsnTR3oiyGws1Dm0YTuxAAeaYGVlGpUsHqloPcFjPg+X0Fj2qODGLNwQOAcCiQmHub/V007kiH5A== + +"@rollup/rollup-win32-x64-msvc@4.44.1": + version "4.44.1" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.1.tgz#1c982f6a5044ffc2a35cd754a0951bdcb44d5ba0" + integrity sha512-J8o22LuF0kTe7m+8PvW9wk3/bRq5+mRo5Dqo6+vXb7otCm3TPhYOJqOaQtGU9YMWQSL3krMnoOxMr0+9E6F3Ug== + +"@standard-schema/spec@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@standard-schema/spec/-/spec-1.0.0.tgz#f193b73dc316c4170f2e82a881da0f550d551b9c" + integrity sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA== + +"@stylistic/eslint-plugin@^5.0.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@stylistic/eslint-plugin/-/eslint-plugin-5.1.0.tgz#98769a3e6fc68d92deba20538341b0ea7923b3ce" + integrity sha512-TJRJul4u/lmry5N/kyCU+7RWWOk0wyXN+BncRlDYBqpLFnzXkd7QGVfN7KewarFIXv0IX0jSF/Ksu7aHWEDeuw== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/types" "^8.34.1" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + estraverse "^5.3.0" + picomatch "^4.0.2" + +"@sveltejs/acorn-typescript@^1.0.5": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz#f518101d1b2e12ce80854f1cd850d3b9fb91d710" + integrity sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ== + +"@types/detect-indent@0.1.30": + version "0.1.30" + resolved "https://registry.yarnpkg.com/@types/detect-indent/-/detect-indent-0.1.30.tgz#dc682bb412b4e65ba098e70edad73b4833fb910d" + integrity sha512-AUmj9JHuHTD94slY1WR1VulFxRGC6D1pcNCN0MCulKFyiihvV/28lLS8oRHgfmc2Cxq954J8Vmosa8qzm7PLGQ== + +"@types/eslint-scope@^3.7.7": + version "3.7.7" + resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.7.tgz#3108bd5f18b0cdb277c867b3dd449c9ed7079ac5" + integrity sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg== + dependencies: + "@types/eslint" "*" + "@types/estree" "*" + +"@types/eslint@*": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-9.6.1.tgz#d5795ad732ce81715f27f75da913004a56751584" + integrity sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.5", "@types/estree@^1.0.6": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/event-calendar__core@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@types/event-calendar__core/-/event-calendar__core-4.4.0.tgz#9a7ae0c7bceb0bcb0c859e9eafe6a16377583b7c" + integrity sha512-8Y4k+acsniRXn1bR0UGgDJE0Qquuk4+Dgx43VS1isIcAK00sfdu2hs726ikuWWzLZGm44ZfYtbq1eM84RtfT4g== + dependencies: + svelte "^5" + +"@types/glob@5.0.30": + version "5.0.30" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.30.tgz#1026409c5625a8689074602808d082b2867b8a51" + integrity sha512-ZM05wDByI+WA153sfirJyEHoYYoIuZ7lA2dB/Gl8ymmpMTR78fNRtDMqa7Z6SdH4fZdLWZNRE6mZpx3XqBOrHw== + dependencies: + "@types/minimatch" "*" + "@types/node" "*" + +"@types/json-schema@*", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.9": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/minimatch@*": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" + integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== + +"@types/mkdirp@0.3.29": + version "0.3.29" + resolved "https://registry.yarnpkg.com/@types/mkdirp/-/mkdirp-0.3.29.tgz#7f2ad7ec55f914482fc9b1ec4bb1ae6028d46066" + integrity sha512-QRLQpFsIQGO2k8pupga9abfei85GKotAtQ+F6xuQmSGomUt6C52TyMiTFpP8kUwuPKr00gNtu3itLlC6gvI/NA== + +"@types/mustache@^4.2.6": + version "4.2.6" + resolved "https://registry.yarnpkg.com/@types/mustache/-/mustache-4.2.6.tgz#9d4f903f4ad373699b253aa1369727bc5042811f" + integrity sha512-t+8/QWTAhOFlrF1IVZqKnMRJi84EgkIK5Kh0p2JV4OLywUvCwJPFxbJAl7XAow7DVIHsF+xW9f1MVzg0L6Szjw== + +"@types/node@*", "@types/node@^24.0.3": + version "24.0.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.0.7.tgz#ee580f7850c7eabaeef61ef96b8d8c04fdf94f53" + integrity sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw== + dependencies: + undici-types "~7.8.0" + +"@types/node@8.0.0": + version "8.0.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.0.tgz#acaa89247afddc7967e9902fd11761dadea1a555" + integrity sha512-j2tekvJCO7j22cs+LO6i0kRPhmQ9MXaPZ55TzOc1lzkN5b6BWqq4AFjl04s1oRRQ1v5rSe+KEvnLUSTonuls/A== + +"@typescript-eslint/eslint-plugin@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.35.0.tgz#515170100ff867445fe0a17ce05c14fc5fd9ca63" + integrity sha512-ijItUYaiWuce0N1SoSMrEd0b6b6lYkYt99pqCPfybd+HKVXtEvYhICfLdwp42MhiI5mp0oq7PKEL+g1cNiz/Eg== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.35.0" + "@typescript-eslint/type-utils" "8.35.0" + "@typescript-eslint/utils" "8.35.0" + "@typescript-eslint/visitor-keys" "8.35.0" + graphemer "^1.4.0" + ignore "^7.0.0" + natural-compare "^1.4.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/parser@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.35.0.tgz#20a0e17778a329a6072722f5ac418d4376b767d2" + integrity sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA== + dependencies: + "@typescript-eslint/scope-manager" "8.35.0" + "@typescript-eslint/types" "8.35.0" + "@typescript-eslint/typescript-estree" "8.35.0" + "@typescript-eslint/visitor-keys" "8.35.0" + debug "^4.3.4" + +"@typescript-eslint/project-service@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.35.0.tgz#00bd77e6845fbdb5684c6ab2d8a400a58dcfb07b" + integrity sha512-41xatqRwWZuhUMF/aZm2fcUsOFKNcG28xqRSS6ZVr9BVJtGExosLAm5A1OxTjRMagx8nJqva+P5zNIGt8RIgbQ== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.35.0" + "@typescript-eslint/types" "^8.35.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.35.0.tgz#8ccb2ab63383544fab98fc4b542d8d141259ff4f" + integrity sha512-+AgL5+mcoLxl1vGjwNfiWq5fLDZM1TmTPYs2UkyHfFhgERxBbqHlNjRzhThJqz+ktBqTChRYY6zwbMwy0591AA== + dependencies: + "@typescript-eslint/types" "8.35.0" + "@typescript-eslint/visitor-keys" "8.35.0" + +"@typescript-eslint/tsconfig-utils@8.35.0", "@typescript-eslint/tsconfig-utils@^8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.35.0.tgz#6e05aeb999999e31d562ceb4fe144f3cbfbd670e" + integrity sha512-04k/7247kZzFraweuEirmvUj+W3bJLI9fX6fbo1Qm2YykuBvEhRTPl8tcxlYO8kZZW+HIXfkZNoasVb8EV4jpA== + +"@typescript-eslint/type-utils@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.35.0.tgz#0201eae9d83ffcc3451ef8c94f53ecfbf2319ecc" + integrity sha512-ceNNttjfmSEoM9PW87bWLDEIaLAyR+E6BoYJQ5PfaDau37UGca9Nyq3lBk8Bw2ad0AKvYabz6wxc7DMTO2jnNA== + dependencies: + "@typescript-eslint/typescript-estree" "8.35.0" + "@typescript-eslint/utils" "8.35.0" + debug "^4.3.4" + ts-api-utils "^2.1.0" + +"@typescript-eslint/types@8.35.0", "@typescript-eslint/types@^8.34.1", "@typescript-eslint/types@^8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.35.0.tgz#e60d062907930e30008d796de5c4170f02618a93" + integrity sha512-0mYH3emanku0vHw2aRLNGqe7EXh9WHEhi7kZzscrMDf6IIRUQ5Jk4wp1QrledE/36KtdZrVfKnE32eZCf/vaVQ== + +"@typescript-eslint/typescript-estree@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.35.0.tgz#86141e6c55b75bc1eaecc0781bd39704de14e52a" + integrity sha512-F+BhnaBemgu1Qf8oHrxyw14wq6vbL8xwWKKMwTMwYIRmFFY/1n/9T/jpbobZL8vp7QyEUcC6xGrnAO4ua8Kp7w== + dependencies: + "@typescript-eslint/project-service" "8.35.0" + "@typescript-eslint/tsconfig-utils" "8.35.0" + "@typescript-eslint/types" "8.35.0" + "@typescript-eslint/visitor-keys" "8.35.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" + +"@typescript-eslint/utils@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.35.0.tgz#aaf0afab5ab51ea2f1897002907eacd9834606d5" + integrity sha512-nqoMu7WWM7ki5tPgLVsmPM8CkqtoPUG6xXGeefM5t4x3XumOEKMoUZPdi+7F+/EotukN4R9OWdmDxN80fqoZeg== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.35.0" + "@typescript-eslint/types" "8.35.0" + "@typescript-eslint/typescript-estree" "8.35.0" + +"@typescript-eslint/visitor-keys@8.35.0": + version "8.35.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.35.0.tgz#93e905e7f1e94d26a79771d1b1eb0024cb159dbf" + integrity sha512-zTh2+1Y8ZpmeQaQVIc/ZZxsx8UzgKJyNg1PTvjzC7WMhPSVS8bfDX34k1SrwOf016qd5RU3az2UxUNue3IfQ5g== + dependencies: + "@typescript-eslint/types" "8.35.0" + eslint-visitor-keys "^4.2.1" + +"@webassemblyjs/ast@1.14.1", "@webassemblyjs/ast@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.14.1.tgz#a9f6a07f2b03c95c8d38c4536a1fdfb521ff55b6" + integrity sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ== + dependencies: + "@webassemblyjs/helper-numbers" "1.13.2" + "@webassemblyjs/helper-wasm-bytecode" "1.13.2" + +"@webassemblyjs/floating-point-hex-parser@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz#fcca1eeddb1cc4e7b6eed4fc7956d6813b21b9fb" + integrity sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA== + +"@webassemblyjs/helper-api-error@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz#e0a16152248bc38daee76dd7e21f15c5ef3ab1e7" + integrity sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ== + +"@webassemblyjs/helper-buffer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz#822a9bc603166531f7d5df84e67b5bf99b72b96b" + integrity sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA== + +"@webassemblyjs/helper-numbers@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz#dbd932548e7119f4b8a7877fd5a8d20e63490b2d" + integrity sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA== + dependencies: + "@webassemblyjs/floating-point-hex-parser" "1.13.2" + "@webassemblyjs/helper-api-error" "1.13.2" + "@xtuc/long" "4.2.2" + +"@webassemblyjs/helper-wasm-bytecode@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz#e556108758f448aae84c850e593ce18a0eb31e0b" + integrity sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA== + +"@webassemblyjs/helper-wasm-section@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz#9629dda9c4430eab54b591053d6dc6f3ba050348" + integrity sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw== + 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" + +"@webassemblyjs/ieee754@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz#1c5eaace1d606ada2c7fd7045ea9356c59ee0dba" + integrity sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw== + dependencies: + "@xtuc/ieee754" "^1.2.0" + +"@webassemblyjs/leb128@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.13.2.tgz#57c5c3deb0105d02ce25fa3fd74f4ebc9fd0bbb0" + integrity sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw== + dependencies: + "@xtuc/long" "4.2.2" + +"@webassemblyjs/utf8@1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.13.2.tgz#917a20e93f71ad5602966c2d685ae0c6c21f60f1" + integrity sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ== + +"@webassemblyjs/wasm-edit@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz#ac6689f502219b59198ddec42dcd496b1004d597" + integrity sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ== + 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" + +"@webassemblyjs/wasm-gen@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz#991e7f0c090cb0bb62bbac882076e3d219da9570" + integrity sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg== + 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" + +"@webassemblyjs/wasm-opt@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz#e6f71ed7ccae46781c206017d3c14c50efa8106b" + integrity sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@webassemblyjs/helper-buffer" "1.14.1" + "@webassemblyjs/wasm-gen" "1.14.1" + "@webassemblyjs/wasm-parser" "1.14.1" + +"@webassemblyjs/wasm-parser@1.14.1", "@webassemblyjs/wasm-parser@^1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz#b3e13f1893605ca78b52c68e54cf6a865f90b9fb" + integrity sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ== + 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" + +"@webassemblyjs/wast-printer@1.14.1": + version "1.14.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz#3bb3e9638a8ae5fdaf9610e7a06b4d9f9aa6fe07" + integrity sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw== + dependencies: + "@webassemblyjs/ast" "1.14.1" + "@xtuc/long" "4.2.2" + +"@webpack-cli/configtest@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-3.0.1.tgz#76ac285b9658fa642ce238c276264589aa2b6b57" + integrity sha512-u8d0pJ5YFgneF/GuvEiDA61Tf1VDomHHYMjv/wc9XzYj7nopltpG96nXN5dJRstxZhcNpV1g+nT6CydO7pHbjA== + +"@webpack-cli/info@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-3.0.1.tgz#3cff37fabb7d4ecaab6a8a4757d3826cf5888c63" + integrity sha512-coEmDzc2u/ffMvuW9aCjoRzNSPDl/XLuhPdlFRpT9tZHmJ/039az33CE7uH+8s0uL1j5ZNtfdv0HkfaKRBGJsQ== + +"@webpack-cli/serve@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-3.0.1.tgz#bd8b1f824d57e30faa19eb78e4c0951056f72f00" + integrity sha512-sbgw03xQaCLiT6gcY/6u3qBDn01CWw/nbaXl3gTdTFuJJ75Gffv3E3DBpgvY2fkkrdS1fpjaXNOmJlnbtKauKg== + +"@xtuc/ieee754@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== + +"@xtuc/long@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.12.1, acorn@^8.14.0, acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +ajv-formats@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-2.1.1.tgz#6e669400659eb74973bbf2e33327180a0996b520" + integrity sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA== + dependencies: + ajv "^8.0.0" + +ajv-keywords@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-5.1.0.tgz#69d4d385a4733cdbeab44964a1170a88f87f0e16" + integrity sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw== + dependencies: + fast-deep-equal "^3.1.3" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0, ajv@^8.9.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +asn1.js@^4.10.1: + version "4.10.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +assert@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/assert/-/assert-2.1.0.tgz#6d92a238d05dc02e7427c881fb8be81c8448b2dd" + integrity sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw== + dependencies: + call-bind "^1.0.2" + is-nan "^1.3.2" + object-is "^1.1.5" + object.assign "^4.1.4" + util "^0.12.5" + +autolinker@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-4.1.5.tgz#e0d45f04c41d62598bf80b809c422f732d3aafde" + integrity sha512-vEfYZPmvVOIuE567XBVCsx8SBgOYtjB2+S1iAaJ+HgH+DNjAcrHem2hmAeC9yaNGWayicv4yR+9UaJlkF3pvtw== + dependencies: + tslib "^2.8.1" + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-64@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a" + integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.9: + version "4.12.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.2.tgz#3d8fed6796c24e177737f7cc5172ee04ef39ec99" + integrity sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw== + +bn.js@^5.2.1: + version "5.2.2" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.2.tgz#82c09f9ebbb17107cd72cb7fd39bd1f9d0aaa566" + integrity sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-resolve@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-2.0.0.tgz#99b7304cb392f8d73dba741bb2d7da28c6d7842b" + integrity sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ== + dependencies: + resolve "^1.17.0" + +browserify-aes@^1.0.4, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + +browserify-cipher@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +browserify-rsa@^4.0.0, browserify-rsa@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.1.tgz#06e530907fe2949dc21fc3c2e2302e10b1437238" + integrity sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ== + dependencies: + bn.js "^5.2.1" + randombytes "^2.1.0" + safe-buffer "^5.2.1" + +browserify-sign@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.3.tgz#7afe4c01ec7ee59a89a558a4b75bd85ae62d4208" + integrity sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw== + dependencies: + bn.js "^5.2.1" + browserify-rsa "^4.1.0" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.5" + hash-base "~3.0" + inherits "^2.0.4" + parse-asn1 "^5.1.7" + readable-stream "^2.3.8" + safe-buffer "^5.2.1" + +browserify-zlib@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== + dependencies: + pako "~1.0.5" + +browserslist@^4.24.0: + version "4.25.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.25.1.tgz#ba9e8e6f298a1d86f829c9b975e07948967bb111" + integrity sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw== + dependencies: + caniuse-lite "^1.0.30001726" + electron-to-chromium "^1.5.173" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + integrity sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +caniuse-lite@^1.0.30001726: + version "1.0.30001726" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001726.tgz#a15bd87d5a4bf01f6b6f70ae7c97fdfd28b5ae47" + integrity sha512-VQAUIUzBiZ/UnlM28fSp2CRF3ivUn1BWEvxMcVTNwpw91Py1pGbPIyIKtd+tzct9C3ouceCVdGAXxZOpZAsgdw== + +chalk@^4.0.0, chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +chrome-trace-event@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.6.tgz#8fe672437d01cd6c4561af5334e0cc50ff1955f7" + integrity sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.14: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-12.1.0.tgz#01423b36f501259fdaac4d0e4d60c96c991585d3" + integrity sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA== + +commander@^2.20.0, commander@^2.9.0: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +console-browserify@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.2.0.tgz#67063cef57ceb6cf4993a2ab3a55840ae8c49336" + integrity sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA== + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + integrity sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +create-ecdh@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + +create-hash@^1.1.0, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hash@~1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + integrity sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +create-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-fetch@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-4.1.0.tgz#8f69355007ee182e47fa692ecbaa37a52e43c3d2" + integrity sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw== + dependencies: + node-fetch "^2.7.0" + +cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-browserify@^3.12.1: + version "3.12.1" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.1.tgz#bb8921bec9acc81633379aa8f52d69b0b69e0dac" + integrity sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ== + dependencies: + browserify-cipher "^1.0.1" + browserify-sign "^4.2.3" + create-ecdh "^4.0.4" + create-hash "^1.2.0" + create-hmac "^1.1.7" + diffie-hellman "^5.0.3" + hash-base "~3.0.4" + inherits "^2.0.4" + pbkdf2 "^3.1.2" + public-encrypt "^4.0.3" + randombytes "^2.1.0" + randomfill "^1.0.4" + +css-loader@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-7.1.2.tgz#64671541c6efe06b0e22e750503106bdd86880f8" + integrity sha512-6WvYYn7l/XEGN8Xu2vWFt9nVzrCn39vKyTEFf/ExEyoksJjjSZV/0/35XPlMbpnr6VGhZIUg5yJrL8tGfes/FA== + 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" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +debug@4.4.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +des.js@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-indent@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-0.2.0.tgz#042914498979ac2d9f3c73e4ff3e6877d3bc92b6" + integrity sha512-C6jyrDu/eGH4KT0ZxAzijiH+ts5YLy7DqGFoDuHGxZjMOdjzRltp3jByySnpFBVIy4Em0ZkLN8tIV6mcREdw5A== + dependencies: + get-stdin "^0.1.0" + minimist "^0.1.0" + +diffie-hellman@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +domain-browser@4.22.0: + version "4.22.0" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-4.22.0.tgz#6ddd34220ec281f9a65d3386d267ddd35c491f9f" + integrity sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw== + +dts-bundle-webpack@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/dts-bundle-webpack/-/dts-bundle-webpack-1.0.2.tgz#c50439a89e71fd9e42800092561c05d5c3ea9ea6" + integrity sha512-/gBQBu5spW8BsGKyYwZeDb+gzDsipisf4Hg0ERPrrS0661cYajVUHARwvts/vfvG5wuv+p295byoNl2da+Re6w== + dependencies: + dts-bundle "^0.7.3" + +dts-bundle@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/dts-bundle/-/dts-bundle-0.7.3.tgz#372b7bb69c820782e6382f400739a69dced3d59a" + integrity sha512-EEAEuPRk8QyKhoN90NHTh+spSQujkkvOnKWUfuzpmC/fgryiWopL1SegSktx0UsoPfNidIGVDN7/AXpBDBv0WQ== + dependencies: + "@types/detect-indent" "0.1.30" + "@types/glob" "5.0.30" + "@types/mkdirp" "0.3.29" + "@types/node" "8.0.0" + commander "^2.9.0" + detect-indent "^0.2.0" + glob "^6.0.4" + mkdirp "^0.5.0" + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +electron-to-chromium@^1.5.173: + version "1.5.177" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.177.tgz#db730d8254959184e65320a3a0b7edcd29c54f60" + integrity sha512-7EH2G59nLsEMj97fpDuvVcYi6lwTcM1xuWw3PssD8xzboAW7zj7iB3COEEEATUfjLHrs5uKBLQT03V/8URx06g== + +elliptic@^6.5.3, elliptic@^6.5.5: + version "6.6.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.6.1.tgz#3b8ffb02670bf69e382c7f65bf524c97c5405c06" + integrity sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +email-addresses@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-5.0.0.tgz#7ae9e7f58eef7d5e3e2c2c2d3ea49b78dc854fa6" + integrity sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enhanced-resolve@^5.0.0, enhanced-resolve@^5.17.1: + version "5.18.2" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz#7903c5b32ffd4b2143eeb4b92472bd68effd5464" + integrity sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +envinfo@^7.14.0: + version "7.14.0" + resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.14.0.tgz#26dac5db54418f2a4c1159153a0b2ae980838aae" + integrity sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg== + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-module-lexer@^1.2.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +esbuild@^0.25.0: + version "0.25.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.5.tgz#71075054993fdfae76c66586f9b9c1f8d7edd430" + integrity sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.5" + "@esbuild/android-arm" "0.25.5" + "@esbuild/android-arm64" "0.25.5" + "@esbuild/android-x64" "0.25.5" + "@esbuild/darwin-arm64" "0.25.5" + "@esbuild/darwin-x64" "0.25.5" + "@esbuild/freebsd-arm64" "0.25.5" + "@esbuild/freebsd-x64" "0.25.5" + "@esbuild/linux-arm" "0.25.5" + "@esbuild/linux-arm64" "0.25.5" + "@esbuild/linux-ia32" "0.25.5" + "@esbuild/linux-loong64" "0.25.5" + "@esbuild/linux-mips64el" "0.25.5" + "@esbuild/linux-ppc64" "0.25.5" + "@esbuild/linux-riscv64" "0.25.5" + "@esbuild/linux-s390x" "0.25.5" + "@esbuild/linux-x64" "0.25.5" + "@esbuild/netbsd-arm64" "0.25.5" + "@esbuild/netbsd-x64" "0.25.5" + "@esbuild/openbsd-arm64" "0.25.5" + "@esbuild/openbsd-x64" "0.25.5" + "@esbuild/sunos-x64" "0.25.5" + "@esbuild/win32-arm64" "0.25.5" + "@esbuild/win32-ia32" "0.25.5" + "@esbuild/win32-x64" "0.25.5" + +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^9.29.0: + version "9.30.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.30.0.tgz#fb0c655f5e28fc1b2f4050c28efa1876d78034fc" + integrity sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.21.0" + "@eslint/config-helpers" "^0.3.0" + "@eslint/core" "^0.14.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.30.0" + "@eslint/plugin-kit" "^0.3.1" + "@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.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +esm-env@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.2.2.tgz#263c9455c55861f41618df31b20cb571fc20b75e" + integrity sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA== + +espree@^10.0.1, espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== + dependencies: + acorn "^8.15.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.1" + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrap@^1.4.8: + version "1.4.9" + resolved "https://registry.yarnpkg.com/esrap/-/esrap-1.4.9.tgz#350362c55d8c83b263edfb0fd48dac95162167de" + integrity sha512-3OMlcd0a03UGuZpPeUC1HxR3nA23l+HEyCiZw3b3FumJIN9KphoGzDJKMXI1S72jVS1dsenDyQC0kJlO1U9E1g== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +events@^3.0.0, events@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + +evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + 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" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-uri@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.0.6.tgz#88f130b77cfaea2378d56bf970dea21257a68748" + integrity sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw== + +fastest-levenshtein@^1.0.12: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fdir@^6.4.4: + version "6.4.6" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.4.6.tgz#2b268c0232697063111bbf3f64810a2a741ba281" + integrity sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +foreground-child@^3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.1.tgz#32e8e9ed1b68a3497befb9ac2b6adf92a638576f" + integrity sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw== + dependencies: + cross-spawn "^7.0.6" + signal-exit "^4.0.1" + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + 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" + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stdin@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-0.1.0.tgz#5998af24aafc802d15c82c685657eeb8b10d4a91" + integrity sha512-/WBu3IaQZxE3bs3BhBmR10ipDY4pjN+U4EZgXULa1eqKA0B/Lka/MVoAqhTVYBkkRlCrEGDOU9itrzIgm9Ksng== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob-to-regexp@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" + integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== + +glob@^11.0.0: + version "11.0.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-11.0.3.tgz#9d8087e6d72ddb3c4707b1d2778f80ea3eaefcd6" + integrity sha512-2Nim7dha1KVkaiF4q6Dj+ngPPMdfvLJEOpZk/jKiUAkqKebpGAWQXAq9z1xu9HKu5lWfqw/FASuccEjyznjPaA== + dependencies: + foreground-child "^3.3.1" + jackspeak "^4.1.1" + minimatch "^10.0.3" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^2.0.0" + +glob@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + integrity sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A== + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-16.2.0.tgz#19efcd1ddde2bd5efce128e5c2e441df1abc6f7c" + integrity sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg== + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + integrity sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw== + dependencies: + inherits "^2.0.1" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash-base@~3.0, hash-base@~3.0.4: + version "3.0.5" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.5.tgz#52480e285395cf7fba17dc4c9e47acdc7f248a8a" + integrity sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg== + dependencies: + inherits "^2.0.4" + safe-buffer "^5.2.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +https-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + integrity sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg== + +ical.js@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/ical.js/-/ical.js-2.2.0.tgz#9c0c2d44c34e34104cc2dc8d24a2e13c0519ac9f" + integrity sha512-P8gjWkTEd5M/SEEvBVPPO/KC+V+HRNRZh3xfCDTVWmUTEfVbL8JaK5GTWS2MJ55aLMhfXhbh7kYzd0nrBARjsA== + +icss-utils@^5.0.0, icss-utils@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +ignore@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@~2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +interpret@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" + integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== + +is-arguments@^1.0.4: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.2.0.tgz#ad58c6aecf563b78ef2bf04df540da8f5d7d8e1b" + integrity sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-function@^1.0.7: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.0.tgz#bf3eeda931201394f57b5dba2800f91a238309ca" + integrity sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ== + dependencies: + call-bound "^1.0.3" + get-proto "^1.0.0" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-nan@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/is-nan/-/is-nan-1.3.2.tgz#043a54adea31748b55b6cd4e09aadafa69bd9e1d" + integrity sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-reference@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.3.tgz#9ef7bf9029c70a67b2152da4adf57c23d718910f" + integrity sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw== + dependencies: + "@types/estree" "^1.0.6" + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-typed-array@^1.1.14, is-typed-array@^1.1.3: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +isomorphic-timers-promises@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz#e4137c24dbc54892de8abae3a4b5c1ffff381598" + integrity sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ== + +jackspeak@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-4.1.1.tgz#96876030f450502047fc7e8c7fcf8ce8124e43ae" + integrity sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + +jest-worker@^27.4.5: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +loader-runner@^4.2.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.3.0.tgz#c1b4a163b99f614830353b16755e7149ac2314e1" + integrity sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg== + +locate-character@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" + integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^11.0.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-11.1.0.tgz#afafb060607108132dbc1cf8ae661afb69486117" + integrity sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A== + +magic-string@^0.30.11, magic-string@^0.30.3: + version "0.30.17" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.17.tgz#450a449673d2460e5bbcfba9a61916a1714c7453" + integrity sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +mdn-data@2.21.0: + version "2.21.0" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.21.0.tgz#f3a495e8b1e60cb4fbeaf9136aefba2f987a56e1" + integrity sha512-+ZKPQezM5vYJIkCxaC+4DTnRrVZR1CgsKLu5zsQERQx6Tea8Y+wMx5A24rq8A8NepCeatIQufVAekKNgiBMsGQ== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.0, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.27: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +"minimatch@2 || 3", minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.3.tgz#cf7a0314a16c4d9ab73a7730a0e8e3c3502d47aa" + integrity sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw== + dependencies: + "@isaacs/brace-expansion" "^5.0.0" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.1.0.tgz#99df657a52574c21c9057497df742790b2b4c0de" + integrity sha512-wR5Ipl99t0mTGwLjQJnBjrP/O7zBbLZqvA3aw32DmLx+nXHfWctUjzDjnDx09pX1Po86WFQazF9xUzfMea3Cnw== + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + +mkdirp@^0.5.0: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mustache@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/mustache/-/mustache-4.2.0.tgz#e5892324d60a12ec9c2a73359edca52972bf6f64" + integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== + +nanoid@^3.3.11: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-polyfill-webpack-plugin@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.1.0.tgz#13115d0e3b1c99d978acffeb8cd3aab55d2a9203" + integrity sha512-b4ei444EKkOagG/yFqojrD3QTYM5IOU1f8tn9o6uwrG4qL+brI7oVhjPVd0ZL2xy+Z6CP5bu9w8XTvlWgiXHcw== + dependencies: + node-stdlib-browser "^1.3.0" + type-fest "^4.27.0" + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +node-stdlib-browser@^1.2.0, node-stdlib-browser@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz#f41fa554f720a3df951e40339f4d92ac512222ac" + integrity sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw== + dependencies: + assert "^2.0.0" + browser-resolve "^2.0.0" + browserify-zlib "^0.2.0" + buffer "^5.7.1" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + create-require "^1.1.1" + crypto-browserify "^3.12.1" + domain-browser "4.22.0" + events "^3.0.0" + https-browserify "^1.0.0" + isomorphic-timers-promises "^1.0.1" + os-browserify "^0.3.0" + path-browserify "^1.0.1" + pkg-dir "^5.0.0" + process "^0.11.10" + punycode "^1.4.1" + querystring-es3 "^0.2.1" + readable-stream "^3.6.0" + stream-browserify "^3.0.0" + stream-http "^3.2.0" + string_decoder "^1.0.0" + timers-browserify "^2.0.4" + tty-browserify "0.0.1" + url "^0.11.4" + util "^0.12.4" + vm-browserify "^1.0.1" + +npm-run-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-6.0.0.tgz#25cfdc4eae04976f3349c0b1afc089052c362537" + integrity sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA== + dependencies: + path-key "^4.0.0" + unicorn-magic "^0.3.0" + +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-is@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.6.tgz#1a6a53aed2dd8f7e6775ff870bea58545956ab07" + integrity sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + 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" + +os-browserify@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + integrity sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + +pako@~1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-asn1@^5.0.0, parse-asn1@^5.1.7: + version "5.1.7" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.7.tgz#73cdaaa822125f9647165625eb45f8a051d2df06" + integrity sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg== + dependencies: + asn1.js "^4.10.1" + browserify-aes "^1.2.0" + evp_bytestokey "^1.0.3" + hash-base "~3.0" + pbkdf2 "^3.1.2" + safe-buffer "^5.2.1" + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.0.tgz#9f052289f23ad8bf9397a2a0425e7b8615c58580" + integrity sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg== + dependencies: + lru-cache "^11.0.0" + minipass "^7.1.2" + +pbkdf2@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.3.tgz#8be674d591d65658113424592a95d1517318dd4b" + integrity sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA== + dependencies: + create-hash "~1.1.3" + create-hmac "^1.1.7" + ripemd160 "=2.0.1" + safe-buffer "^5.2.1" + sha.js "^2.4.11" + to-buffer "^1.2.0" + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.2.tgz#77c742931e8f3b8820946c76cd0c1f13730d1dab" + integrity sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-dir@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" + integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== + dependencies: + find-up "^5.0.0" + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +postcss-modules-extract-imports@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.1.0.tgz#b4497cb85a9c0c4b5aabeb759bb25e8d89f15002" + integrity sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q== + +postcss-modules-local-by-default@^4.0.5: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.2.0.tgz#d150f43837831dae25e4085596e84f6f5d6ec368" + integrity sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw== + dependencies: + icss-utils "^5.0.0" + postcss-selector-parser "^7.0.0" + postcss-value-parser "^4.1.0" + +postcss-modules-scope@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.2.1.tgz#1bbccddcb398f1d7a511e0a2d1d047718af4078c" + integrity sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA== + dependencies: + postcss-selector-parser "^7.0.0" + +postcss-modules-values@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== + dependencies: + icss-utils "^5.0.0" + +postcss-selector-parser@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz#4d6af97eba65d73bc4d84bcb343e865d7dd16262" + integrity sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.4.33, postcss@^8.5.3: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +public-encrypt@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + +punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + integrity sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +qs@^6.12.3: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + +querystring-es3@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + integrity sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +randomfill@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + +readable-stream@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + 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" + +readable-stream@^3.5.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +rechoir@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.8.0.tgz#49f866e0d32146142da3ad8f0eff352b3215ff22" + integrity sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ== + dependencies: + resolve "^1.20.0" + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.17.0, resolve@^1.20.0: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rimraf@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.0.1.tgz#ffb8ad8844dd60332ab15f52bc104bc3ed71ea4e" + integrity sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A== + dependencies: + glob "^11.0.0" + package-json-from-dist "^1.0.0" + +ripemd160@=2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + integrity sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w== + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rollup@^4.34.9: + version "4.44.1" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.44.1.tgz#641723932894e7acbe6052aea34b8e72ef8b7c8f" + integrity sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.44.1" + "@rollup/rollup-android-arm64" "4.44.1" + "@rollup/rollup-darwin-arm64" "4.44.1" + "@rollup/rollup-darwin-x64" "4.44.1" + "@rollup/rollup-freebsd-arm64" "4.44.1" + "@rollup/rollup-freebsd-x64" "4.44.1" + "@rollup/rollup-linux-arm-gnueabihf" "4.44.1" + "@rollup/rollup-linux-arm-musleabihf" "4.44.1" + "@rollup/rollup-linux-arm64-gnu" "4.44.1" + "@rollup/rollup-linux-arm64-musl" "4.44.1" + "@rollup/rollup-linux-loongarch64-gnu" "4.44.1" + "@rollup/rollup-linux-powerpc64le-gnu" "4.44.1" + "@rollup/rollup-linux-riscv64-gnu" "4.44.1" + "@rollup/rollup-linux-riscv64-musl" "4.44.1" + "@rollup/rollup-linux-s390x-gnu" "4.44.1" + "@rollup/rollup-linux-x64-gnu" "4.44.1" + "@rollup/rollup-linux-x64-musl" "4.44.1" + "@rollup/rollup-win32-arm64-msvc" "4.44.1" + "@rollup/rollup-win32-ia32-msvc" "4.44.1" + "@rollup/rollup-win32-x64-msvc" "4.44.1" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +sax@^1.2.4: + version "1.4.1" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" + integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== + +schema-utils@^4.3.0, schema-utils@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-4.3.2.tgz#0c10878bf4a73fd2b1dfd14b9462b26788c806ae" + integrity sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ== + dependencies: + "@types/json-schema" "^7.0.9" + ajv "^8.9.0" + ajv-formats "^2.1.1" + ajv-keywords "^5.1.0" + +semver@^7.3.4, semver@^7.5.4, semver@^7.6.0: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + 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" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + 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" + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +source-map-js@^1.0.1, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map-support@~0.5.20: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +stream-browserify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" + integrity sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA== + dependencies: + inherits "~2.0.4" + readable-stream "^3.5.0" + +stream-http@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-3.2.0.tgz#1872dfcf24cb15752677e40e5c3f9cc1926028b5" + integrity sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A== + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.4" + readable-stream "^3.6.0" + xtend "^4.0.2" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +string_decoder@^1.0.0, string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1, strip-ansi@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +style-loader@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-4.0.0.tgz#0ea96e468f43c69600011e0589cb05c44f3b17a5" + integrity sha512-1V4WqhhZZgjVAVJyt7TdDPZoPBPNHbekX4fWnCJL1yQukhCeZhJySUL+gL9y6sNdN95uEOS83Y55SqHcP7MzLA== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +svelte@^5, svelte@^5.34.8: + version "5.34.9" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-5.34.9.tgz#c649e45821679c70c2c5cedf1ba1a2355dcb02bf" + integrity sha512-sld35zFpooaSRSj4qw8Vl/cyyK0/sLQq9qhJ7BGZo/Kd0ggYtEnvNYLlzhhoqYsYQzA0hJqkzt3RBO/8KoTZOg== + dependencies: + "@ampproject/remapping" "^2.3.0" + "@jridgewell/sourcemap-codec" "^1.5.0" + "@sveltejs/acorn-typescript" "^1.0.5" + "@types/estree" "^1.0.5" + acorn "^8.12.1" + aria-query "^5.3.1" + axobject-query "^4.1.0" + clsx "^2.1.1" + esm-env "^1.2.1" + esrap "^1.4.8" + is-reference "^3.0.3" + locate-character "^3.0.0" + magic-string "^0.30.11" + zimmerframe "^1.1.2" + +tapable@^2.1.1, tapable@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.2.tgz#ab4984340d30cb9989a490032f086dbb8b56d872" + integrity sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg== + +terser-webpack-plugin@^5.3.11: + version "5.3.14" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.14.tgz#9031d48e57ab27567f02ace85c7d690db66c3e06" + integrity sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw== + 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" + +terser@^5.31.1: + version "5.43.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.43.1.tgz#88387f4f9794ff1a29e7ad61fb2932e25b4fdb6d" + integrity sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg== + dependencies: + "@jridgewell/source-map" "^0.3.3" + acorn "^8.14.0" + commander "^2.20.0" + source-map-support "~0.5.20" + +timers-browserify@^2.0.4: + version "2.0.12" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" + integrity sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ== + dependencies: + setimmediate "^1.0.4" + +timezones-ical-library@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/timezones-ical-library/-/timezones-ical-library-1.10.0.tgz#7cbfcae7d670c28f1ce2b2a0fcc04995d45c0799" + integrity sha512-aSwylC0FyyxMqMjkuaYz56HBhhooYabGT74CbTuY1uOeIcBXSQTXf+u/mTR0MWJFPQDe21REjex+4wt0OdFDpA== + +tiny-invariant@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.3.tgz#46680b7a873a0d5d10005995eb90a70d74d60127" + integrity sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg== + +tinyglobby@^0.2.13: + version "0.2.14" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.14.tgz#5280b0cf3f972b050e74ae88406c0a6a58f4079d" + integrity sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ== + dependencies: + fdir "^6.4.4" + picomatch "^4.0.2" + +to-buffer@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.2.1.tgz#2ce650cdb262e9112a18e65dc29dcb513c8155e0" + integrity sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ== + dependencies: + isarray "^2.0.5" + safe-buffer "^5.2.1" + typed-array-buffer "^1.0.3" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-api-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== + +ts-ics@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/ts-ics/-/ts-ics-2.1.8.tgz#801cdb1ab716e58187ab80f340440d7d79e85230" + integrity sha512-OxmvHHVe2mx1KPRODbtkguA/x4A5abqoDfEc3/+78+jJ0ilrdgXahkf773dn2ZmMGnK4+d5/hWSX2N1HsPyI+w== + dependencies: + "@standard-schema/spec" "^1.0.0" + +ts-loader@^9.5.2: + version "9.5.2" + resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-9.5.2.tgz#1f3d7f4bb709b487aaa260e8f19b301635d08020" + integrity sha512-Qo4piXvOTWcMGIgRiuFa6nHNm+54HbYaZCKqc9eeZCLRy3XqafQgwX2F7mofrbJG3g7EEb+lkiR+z2Lic2s3Zw== + dependencies: + chalk "^4.1.0" + enhanced-resolve "^5.0.0" + micromatch "^4.0.0" + semver "^7.3.4" + source-map "^0.7.4" + +tsdav@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/tsdav/-/tsdav-2.1.5.tgz#6658e57a8fd3b56030c226d2a835336eb02207b3" + integrity sha512-ZUNFysY8Dr11I7aVpFmjk6apvHCMSmOPKGz8Wc1F/8BPn/kVS50LR2T8eCsdF5u+h8hrZrQhC0HWD5d2CCov+g== + dependencies: + base-64 "1.0.0" + cross-fetch "4.1.0" + debug "4.4.1" + xml-js "1.6.11" + +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tty-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.1.tgz#3f05251ee17904dfd0677546670db9651682b811" + integrity sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^4.27.0: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typescript-eslint@^8.35.0: + version "8.35.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.35.0.tgz#65afcdde973614b8f44fa89293919420ca9b904e" + integrity sha512-uEnz70b7kBz6eg/j0Czy6K5NivaYopgxRjsnAJ2Fx5oTLo3wefTHIbL7AkQr1+7tJCRVpTs/wiM8JR/11Loq9A== + dependencies: + "@typescript-eslint/eslint-plugin" "8.35.0" + "@typescript-eslint/parser" "8.35.0" + "@typescript-eslint/utils" "8.35.0" + +typescript@^5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +undici-types@~7.8.0: + version "7.8.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.8.0.tgz#de00b85b710c54122e44fbfd911f8d70174cd294" + integrity sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw== + +unicorn-magic@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104" + integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA== + +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url@^0.11.4: + version "0.11.4" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.4.tgz#adca77b3562d56b72746e76b330b7f27b6721f3c" + integrity sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg== + dependencies: + punycode "^1.4.1" + qs "^6.12.3" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +util@^0.12.4, util@^0.12.5: + version "0.12.5" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.5.tgz#5f17a6059b73db61a875668781a1c2b136bd6fbc" + integrity sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + which-typed-array "^1.1.2" + +vite-plugin-checker@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/vite-plugin-checker/-/vite-plugin-checker-0.9.3.tgz#f6665dba3d6fa8ef5a559e35e546abc33e5f6074" + integrity sha512-Tf7QBjeBtG7q11zG0lvoF38/2AVUzzhMNu+Wk+mcsJ00Rk/FpJ4rmUviVJpzWkagbU13cGXvKpt7CMiqtxVTbQ== + dependencies: + "@babel/code-frame" "^7.27.1" + chokidar "^4.0.3" + npm-run-path "^6.0.0" + picocolors "^1.1.1" + picomatch "^4.0.2" + strip-ansi "^7.1.0" + tiny-invariant "^1.3.3" + tinyglobby "^0.2.13" + vscode-uri "^3.1.0" + +vite-plugin-node-polyfills@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/vite-plugin-node-polyfills/-/vite-plugin-node-polyfills-0.23.0.tgz#99d0d1524fa75ce5c7bb1fc8af30283379e9c684" + integrity sha512-4n+Ys+2bKHQohPBKigFlndwWQ5fFKwaGY6muNDMTb0fSQLyBzS+jjUNRZG9sKF0S/Go4ApG6LFnUGopjkILg3w== + dependencies: + "@rollup/plugin-inject" "^5.0.5" + node-stdlib-browser "^1.2.0" + +vite@^6.3.5: + version "6.3.5" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.3.5.tgz#fec73879013c9c0128c8d284504c6d19410d12a3" + integrity sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.4" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.13" + optionalDependencies: + fsevents "~2.3.3" + +vm-browserify@^1.0.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" + integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== + +vscode-uri@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c" + integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ== + +watchpack@^2.4.1: + version "2.4.4" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.4.tgz#473bda72f0850453da6425081ea46fc0d7602947" + integrity sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA== + dependencies: + glob-to-regexp "^0.4.1" + graceful-fs "^4.1.2" + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +webpack-cli@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-6.0.1.tgz#a1ce25da5ba077151afd73adfa12e208e5089207" + integrity sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw== + dependencies: + "@discoveryjs/json-ext" "^0.6.1" + "@webpack-cli/configtest" "^3.0.1" + "@webpack-cli/info" "^3.0.1" + "@webpack-cli/serve" "^3.0.1" + colorette "^2.0.14" + commander "^12.1.0" + cross-spawn "^7.0.3" + envinfo "^7.14.0" + fastest-levenshtein "^1.0.12" + import-local "^3.0.2" + interpret "^3.1.1" + rechoir "^0.8.0" + webpack-merge "^6.0.1" + +webpack-merge@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-6.0.1.tgz#50c776868e080574725abc5869bd6e4ef0a16c6a" + integrity sha512-hXXvrjtx2PLYx4qruKl+kyRSLc52V+cCvMxRjmKwoA+CBbbF5GfIBtR6kCvl0fYGqTUPKB+1ktVmTHqMOzgCBg== + dependencies: + clone-deep "^4.0.1" + flat "^5.0.2" + wildcard "^2.0.1" + +webpack-sources@^3.2.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.3.3.tgz#d4bf7f9909675d7a070ff14d0ef2a4f3c982c723" + integrity sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg== + +webpack@^5.99.9: + version "5.99.9" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.99.9.tgz#d7de799ec17d0cce3c83b70744b4aedb537d8247" + integrity sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg== + dependencies: + "@types/eslint-scope" "^3.7.7" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + "@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.2" + tapable "^2.1.1" + terser-webpack-plugin "^5.3.11" + watchpack "^2.4.1" + webpack-sources "^3.2.3" + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which-typed-array@^1.1.16, which-typed-array@^1.1.2: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.1.tgz#5ab10d02487198954836b6349f74fff961e10f67" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xml-js@1.6.11: + version "1.6.11" + resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + +xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zimmerframe@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/zimmerframe/-/zimmerframe-1.1.2.tgz#5b75f1fa83b07ae2a428d51e50f58e2ae6855e5e" + integrity sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w== diff --git a/src/frontend/yarn.lock b/src/frontend/yarn.lock new file mode 100644 index 0000000..c62ff84 --- /dev/null +++ b/src/frontend/yarn.lock @@ -0,0 +1,8473 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.5.tgz#a8a4962e1567121ac0b3b487f52107443b455c7f" + integrity sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.24.4", "@babel/core@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.5.tgz#4c81b35e51e1b734f510c99b07dfbc7bbbb48f7e" + integrity sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-compilation-targets" "^7.27.2" + "@babel/helper-module-transforms" "^7.28.3" + "@babel/helpers" "^7.28.4" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/traverse" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/remapping" "^2.3.5" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.28.5", "@babel/generator@^7.7.2": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.5.tgz#712722d5e50f44d07bc7ac9fe84438742dd61298" + integrity sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ== + dependencies: + "@babel/parser" "^7.28.5" + "@babel/types" "^7.28.5" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.28.3": + version "7.28.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz#a2b37d3da3b2344fe085dab234426f2b9a2fa5f6" + integrity sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.28.3" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1", "@babel/helper-validator-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.28.4": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.4.tgz#fe07274742e95bdf7cf1443593eeb8926ab63827" + integrity sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w== + dependencies: + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.4" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.4", "@babel/parser@^7.27.2", "@babel/parser@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.5.tgz#0b0225ee90362f030efd644e8034c99468893b08" + integrity sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ== + dependencies: + "@babel/types" "^7.28.5" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" + integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-jsx-self@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz#af678d8506acf52c577cac73ff7fe6615c85fc92" + integrity sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-transform-react-jsx-source@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz#dcfe2c24094bb757bf73960374e7c55e434f19f0" + integrity sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/runtime@^7.0.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.24.5", "@babel/runtime@^7.27.6", "@babel/runtime@^7.9.2": + version "7.28.4" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.28.4.tgz#a70226016fabe25c5783b2f22d3e1c9bc5ca3326" + integrity sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ== + +"@babel/template@^7.27.2", "@babel/template@^7.3.3": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.3", "@babel/traverse@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.5.tgz#450cab9135d21a7a2ca9d2d35aa05c20e68c360b" + integrity sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.28.5" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.5" + "@babel/template" "^7.27.2" + "@babel/types" "^7.28.5" + debug "^4.3.1" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.28.2", "@babel/types@^7.28.4", "@babel/types@^7.28.5", "@babel/types@^7.3.3": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.5.tgz#10fc405f60897c35f07e85493c932c7b5ca0592b" + integrity sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@dnd-kit/accessibility@^3.1.1": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/accessibility/-/accessibility-3.1.1.tgz#3b4202bd6bb370a0730f6734867785919beac6af" + integrity sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw== + dependencies: + tslib "^2.0.0" + +"@dnd-kit/core@6.3.1": + version "6.3.1" + resolved "https://registry.yarnpkg.com/@dnd-kit/core/-/core-6.3.1.tgz#4c36406a62c7baac499726f899935f93f0e6d003" + integrity sha512-xkGBRQQab4RLwgXxoqETICr6S5JlogafbhNsidmrkVv2YRs5MLwpjoF2qpiGjQt8S9AoxtIV603s0GIUpY5eYQ== + dependencies: + "@dnd-kit/accessibility" "^3.1.1" + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/modifiers@9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/modifiers/-/modifiers-9.0.0.tgz#96a0280c77b10c716ef79d9792ce7ad04370771d" + integrity sha512-ybiLc66qRGuZoC20wdSSG6pDXFikui/dCNGthxv4Ndy8ylErY0N3KVxY2bgo7AWwIbxDmXDg3ylAFmnrjcbVvw== + dependencies: + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/sortable@10.0.0": + version "10.0.0" + resolved "https://registry.yarnpkg.com/@dnd-kit/sortable/-/sortable-10.0.0.tgz#1f9382b90d835cd5c65d92824fa9dafb78c4c3e8" + integrity sha512-+xqhmIIzvAYMGfBYYnbKuNicfSsk4RksY2XdmJhT+HAC01nix6fHCztU68jooFiMUB01Ky3F0FyOvhG/BZrWkg== + dependencies: + "@dnd-kit/utilities" "^3.2.2" + tslib "^2.0.0" + +"@dnd-kit/utilities@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@dnd-kit/utilities/-/utilities-3.2.2.tgz#5a32b6af356dc5f74d61b37d6f7129a4040ced7b" + integrity sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg== + dependencies: + tslib "^2.0.0" + +"@emnapi/core@^1.4.3": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/core/-/core-1.7.1.tgz#3a79a02dbc84f45884a1806ebb98e5746bdfaac4" + integrity sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg== + dependencies: + "@emnapi/wasi-threads" "1.1.0" + tslib "^2.4.0" + +"@emnapi/runtime@^1.4.3", "@emnapi/runtime@^1.7.0": + version "1.7.1" + resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791" + integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA== + dependencies: + tslib "^2.4.0" + +"@emnapi/wasi-threads@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz#60b2102fddc9ccb78607e4a3cf8403ea69be41bf" + integrity sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ== + dependencies: + tslib "^2.4.0" + +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/aix-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz#80fcbe36130e58b7670511e888b8e88a259ed76c" + integrity sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz#8aa4965f8d0a7982dc21734bf6601323a66da752" + integrity sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.25.12.tgz#300712101f7f50f1d2627a162e6e09b109b6767a" + integrity sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/android-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.25.12.tgz#87dfb27161202bdc958ef48bb61b09c758faee16" + integrity sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz#79197898ec1ff745d21c071e1c7cc3c802f0c1fd" + integrity sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/darwin-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz#146400a8562133f45c4d2eadcf37ddd09718079e" + integrity sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz#1c5f9ba7206e158fd2b24c59fa2d2c8bb47ca0fe" + integrity sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/freebsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz#ea631f4a36beaac4b9279fa0fcc6ca29eaeeb2b3" + integrity sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz#e1066bce58394f1b1141deec8557a5f0a22f5977" + integrity sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-arm@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz#452cd66b20932d08bdc53a8b61c0e30baf4348b9" + integrity sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz#b24f8acc45bcf54192c7f2f3be1b53e6551eafe0" + integrity sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-loong64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz#f9cfffa7fc8322571fbc4c8b3268caf15bd81ad0" + integrity sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-mips64el@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz#575a14bd74644ffab891adc7d7e60d275296f2cd" + integrity sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-ppc64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz#75b99c70a95fbd5f7739d7692befe60601591869" + integrity sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-riscv64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz#2e3259440321a44e79ddf7535c325057da875cd6" + integrity sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-s390x@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz#17676cabbfe5928da5b2a0d6df5d58cd08db2663" + integrity sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/linux-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz#0583775685ca82066d04c3507f09524d3cd7a306" + integrity sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw== + +"@esbuild/netbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz#f04c4049cb2e252fe96b16fed90f70746b13f4a4" + integrity sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/netbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz#77da0d0a0d826d7c921eea3d40292548b258a076" + integrity sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ== + +"@esbuild/openbsd-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz#6296f5867aedef28a81b22ab2009c786a952dccd" + integrity sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/openbsd-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz#f8d23303360e27b16cf065b23bbff43c14142679" + integrity sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw== + +"@esbuild/openharmony-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz#49e0b768744a3924be0d7fd97dd6ce9b2923d88d" + integrity sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/sunos-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz#a6ed7d6778d67e528c81fb165b23f4911b9b13d6" + integrity sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-arm64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz#9ac14c378e1b653af17d08e7d3ce34caef587323" + integrity sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-ia32@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz#918942dcbbb35cc14fca39afb91b5e6a3d127267" + integrity sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@esbuild/win32-x64@0.25.12": + version "0.25.12" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz#9bdad8176be7811ad148d1f8772359041f46c6c5" + integrity sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.7.0", "@eslint-community/eslint-utils@^4.8.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3" + integrity sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.19.0": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" + integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-array@^0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== + dependencies: + "@eslint/object-schema" "^2.1.7" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/config-helpers@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== + dependencies: + "@eslint/core" "^0.17.0" + +"@eslint/core@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12" + integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.13.0.tgz#bf02f209846d3bf996f9e8009db62df2739b458c" + integrity sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== + 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" + +"@eslint/eslintrc@^3.2.0", "@eslint/eslintrc@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" + integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== + 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" + +"@eslint/js@9.20.0": + version "9.20.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4" + integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ== + +"@eslint/js@9.39.1", "@eslint/js@^9.25.0": + version "9.39.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.1.tgz#0dd59c3a9f40e3f1882975c321470969243e0164" + integrity sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw== + +"@eslint/object-schema@^2.1.6", "@eslint/object-schema@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== + +"@eslint/plugin-kit@^0.2.5": + version "0.2.8" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz#47488d8f8171b5d4613e833313f3ce708e3525f8" + integrity sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA== + dependencies: + "@eslint/core" "^0.13.0" + levn "^0.4.1" + +"@eslint/plugin-kit@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== + dependencies: + "@eslint/core" "^0.17.0" + levn "^0.4.1" + +"@fontsource-variable/roboto-flex@5.2.5": + version "5.2.5" + resolved "https://registry.yarnpkg.com/@fontsource-variable/roboto-flex/-/roboto-flex-5.2.5.tgz#38368ea754697c2fdf08df11b06e8b6d391ff4c1" + integrity sha512-yrZ9rWNvfM4IBqJSpoFV4wC1GaKNwpzhihyBke+N3WiA0Y7LYxwj6kvvHgecabVIHFL3ZZJTwj3KcKOCyASFPg== + +"@fontsource/material-icons-outlined@5.2.5": + version "5.2.5" + resolved "https://registry.yarnpkg.com/@fontsource/material-icons-outlined/-/material-icons-outlined-5.2.5.tgz#16b4b2a8dcd1fbd69d4182792a65f7b41b8cb230" + integrity sha512-soAUWorSKrLN0a7wk74pedV0ZxhLaMD40DuUTMIqTpDcdJ/pxaG+/OcXtMEzx2+5K5FwL7yS525ZInAzPG051Q== + +"@fontsource/material-icons@5.2.5": + version "5.2.5" + resolved "https://registry.yarnpkg.com/@fontsource/material-icons/-/material-icons-5.2.5.tgz#cdb9dd23c0da4b021c866dc529ed4c203414ec3c" + integrity sha512-9k0LBRVgResIeD+vC/epYmm/awN2k2L8twwEtUWQ3FHluMi+7PbISOpXqksvfqPn9FJy4/KEeWOhFTR/SrbhNw== + +"@formatjs/ecma402-abstract@2.3.6": + version "2.3.6" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-2.3.6.tgz#d6ca9d3579054fe1e1a0a0b5e872e0d64922e4e1" + integrity sha512-HJnTFeRM2kVFVr5gr5kH1XP6K0JcJtE7Lzvtr3FS/so5f1kpsqqqxy5JF+FRaO6H2qmcMfAUIox7AJteieRtVw== + dependencies: + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/intl-localematcher" "0.6.2" + decimal.js "^10.4.3" + tslib "^2.8.0" + +"@formatjs/fast-memoize@2.2.7": + version "2.2.7" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-2.2.7.tgz#707f9ddaeb522a32f6715bb7950b0831f4cc7b15" + integrity sha512-Yabmi9nSvyOMrlSeGGWDiH7rf3a7sIwplbvo/dlz9WCIjzIQAfy1RMf4S0X3yG724n5Ghu2GmEl5NJIV6O9sZQ== + dependencies: + tslib "^2.8.0" + +"@formatjs/icu-messageformat-parser@2.11.4": + version "2.11.4" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.11.4.tgz#63bd2cd82d08ae2bef55adeeb86486df68826f32" + integrity sha512-7kR78cRrPNB4fjGFZg3Rmj5aah8rQj9KPzuLsmcSn4ipLXQvC04keycTI1F7kJYDwIXtT2+7IDEto842CfZBtw== + dependencies: + "@formatjs/ecma402-abstract" "2.3.6" + "@formatjs/icu-skeleton-parser" "1.8.16" + tslib "^2.8.0" + +"@formatjs/icu-skeleton-parser@1.8.16": + version "1.8.16" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.8.16.tgz#13f81f6845c7cf6599623006aacaf7d6b4ad2970" + integrity sha512-H13E9Xl+PxBd8D5/6TVUluSpxGNvFSlN/b3coUp0e0JpuWXXnQDiavIpY3NnvSp4xhEMoXyyBvVfdFX8jglOHQ== + dependencies: + "@formatjs/ecma402-abstract" "2.3.6" + tslib "^2.8.0" + +"@formatjs/intl-localematcher@0.6.2": + version "0.6.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.6.2.tgz#e9ebe0b4082d7d48e5b2d753579fb7ece4eaefea" + integrity sha512-XOMO2Hupl0wdd172Y06h6kLpBz6Dv+J4okPLl4LPtzbr8f66WbIoy4ev98EBuZ6ZK4h5ydTN6XneT4QVpD7cdA== + dependencies: + tslib "^2.8.0" + +"@gouvfr-lasuite/integration@1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@gouvfr-lasuite/integration/-/integration-1.0.2.tgz#ed0000f4b738c5a19bb60f5b80a9a2f5d9414234" + integrity sha512-npOotZQSyu6SffHiPP+jQVOkJ3qW2KE2cANhEK92sNLX9uZqQaCqljO5GhzsBmh0lB76fiXnrr9i8SIpnDUSZg== + +"@gouvfr-lasuite/ui-kit@0.18.4": + version "0.18.4" + resolved "https://registry.yarnpkg.com/@gouvfr-lasuite/ui-kit/-/ui-kit-0.18.4.tgz#536a8e1873d3eca80d0734735d87d3eec4934938" + integrity sha512-D/oUexk73khJHBERr0l2S7uVMziUkPpnlrO2+JeTFGCr/7LwAdNBoxnbsVMBlb+S6WeNAkJQV53DmalTLs6GlA== + dependencies: + "@dnd-kit/core" "6.3.1" + "@dnd-kit/modifiers" "9.0.0" + "@dnd-kit/sortable" "10.0.0" + "@fontsource/material-icons" "5.2.5" + "@gouvfr-lasuite/integration" "1.0.2" + "@openfun/cunningham-react" "4.0.0" + "@types/node" "22.10.7" + clsx "2.1.1" + cmdk "1.0.4" + react-arborist "3.4.3" + react-aria-components "1.8.0" + react-resizable-panels "2.1.7" + react-stately "3.37.0" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.7" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.4.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.1", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== + +"@img/colour@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.0.0.tgz#d2fabb223455a793bf3bf9c70de3d28526aa8311" + integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw== + +"@img/sharp-darwin-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz#6e0732dcade126b6670af7aa17060b926835ea86" + integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w== + optionalDependencies: + "@img/sharp-libvips-darwin-arm64" "1.2.4" + +"@img/sharp-darwin-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz#19bc1dd6eba6d5a96283498b9c9f401180ee9c7b" + integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw== + optionalDependencies: + "@img/sharp-libvips-darwin-x64" "1.2.4" + +"@img/sharp-libvips-darwin-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz#2894c0cb87d42276c3889942e8e2db517a492c43" + integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g== + +"@img/sharp-libvips-darwin-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz#e63681f4539a94af9cd17246ed8881734386f8cc" + integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg== + +"@img/sharp-libvips-linux-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz#b1b288b36864b3bce545ad91fa6dadcf1a4ad318" + integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw== + +"@img/sharp-libvips-linux-arm@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz#b9260dd1ebe6f9e3bdbcbdcac9d2ac125f35852d" + integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A== + +"@img/sharp-libvips-linux-ppc64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz#4b83ecf2a829057222b38848c7b022e7b4d07aa7" + integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA== + +"@img/sharp-libvips-linux-riscv64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz#880b4678009e5a2080af192332b00b0aaf8a48de" + integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA== + +"@img/sharp-libvips-linux-s390x@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz#74f343c8e10fad821b38f75ced30488939dc59ec" + integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ== + +"@img/sharp-libvips-linux-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz#df4183e8bd8410f7d61b66859a35edeab0a531ce" + integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw== + +"@img/sharp-libvips-linuxmusl-arm64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz#c8d6b48211df67137541007ee8d1b7b1f8ca8e06" + integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw== + +"@img/sharp-libvips-linuxmusl-x64@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz#be11c75bee5b080cbee31a153a8779448f919f75" + integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg== + +"@img/sharp-linux-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz#7aa7764ef9c001f15e610546d42fce56911790cc" + integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg== + optionalDependencies: + "@img/sharp-libvips-linux-arm64" "1.2.4" + +"@img/sharp-linux-arm@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz#5fb0c3695dd12522d39c3ff7a6bc816461780a0d" + integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw== + optionalDependencies: + "@img/sharp-libvips-linux-arm" "1.2.4" + +"@img/sharp-linux-ppc64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz#9c213a81520a20caf66978f3d4c07456ff2e0813" + integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA== + optionalDependencies: + "@img/sharp-libvips-linux-ppc64" "1.2.4" + +"@img/sharp-linux-riscv64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz#cdd28182774eadbe04f62675a16aabbccb833f60" + integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw== + optionalDependencies: + "@img/sharp-libvips-linux-riscv64" "1.2.4" + +"@img/sharp-linux-s390x@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz#93eac601b9f329bb27917e0e19098c722d630df7" + integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg== + optionalDependencies: + "@img/sharp-libvips-linux-s390x" "1.2.4" + +"@img/sharp-linux-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz#55abc7cd754ffca5002b6c2b719abdfc846819a8" + integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ== + optionalDependencies: + "@img/sharp-libvips-linux-x64" "1.2.4" + +"@img/sharp-linuxmusl-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz#d6515ee971bb62f73001a4829b9d865a11b77086" + integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + +"@img/sharp-linuxmusl-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz#d97978aec7c5212f999714f2f5b736457e12ee9f" + integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q== + optionalDependencies: + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + +"@img/sharp-wasm32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz#2f15803aa626f8c59dd7c9d0bbc766f1ab52cfa0" + integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw== + dependencies: + "@emnapi/runtime" "^1.7.0" + +"@img/sharp-win32-arm64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz#3706e9e3ac35fddfc1c87f94e849f1b75307ce0a" + integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g== + +"@img/sharp-win32-ia32@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz#0b71166599b049e032f085fb9263e02f4e4788de" + integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg== + +"@img/sharp-win32-x64@0.34.5": + version "0.34.5" + resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz#a81ffb00e69267cd0a1d626eaedb8a8430b2b2f8" + integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw== + +"@internationalized/date@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.8.0.tgz#24fb301029224351381aa87cba853ca1093af094" + integrity sha512-J51AJ0fEL68hE4CwGPa6E0PO6JDaVLd8aln48xFCSy7CZkZc96dGEGmLs2OEEbBxcsVZtfrqkXJwI2/MSG8yKw== + dependencies: + "@swc/helpers" "^0.5.0" + +"@internationalized/date@^3.10.0", "@internationalized/date@^3.8.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@internationalized/date/-/date-3.10.0.tgz#056db64a4facdf48c6937ad498a882a8151d640a" + integrity sha512-oxDR/NTEJ1k+UFVQElaNIk65E/Z83HK1z1WI3lQyhTtnNg4R5oVXaPzK3jcpKG8UHKDVuDQHzn+wsxSz8RP3aw== + dependencies: + "@swc/helpers" "^0.5.0" + +"@internationalized/message@^3.1.7", "@internationalized/message@^3.1.8": + version "3.1.8" + resolved "https://registry.yarnpkg.com/@internationalized/message/-/message-3.1.8.tgz#7181e8178f0868535f4507a573bf285e925832cb" + integrity sha512-Rwk3j/TlYZhn3HQ6PyXUV0XP9Uv42jqZGNegt0BXlxjE6G3+LwHjbQZAGHhCnCPdaA6Tvd3ma/7QzLlLkJxAWA== + dependencies: + "@swc/helpers" "^0.5.0" + intl-messageformat "^10.1.0" + +"@internationalized/number@^3.6.1", "@internationalized/number@^3.6.5": + version "3.6.5" + resolved "https://registry.yarnpkg.com/@internationalized/number/-/number-3.6.5.tgz#1103f2832ca8d9dd3e4eecf95733d497791dbbbe" + integrity sha512-6hY4Kl4HPBvtfS62asS/R22JzNNy8vi/Ssev7x6EobfCp+9QIB2hKvI2EtbdJ0VSQacxVNtqhE/NmF/NZ0gm6g== + dependencies: + "@swc/helpers" "^0.5.0" + +"@internationalized/string@^3.2.6", "@internationalized/string@^3.2.7": + version "3.2.7" + resolved "https://registry.yarnpkg.com/@internationalized/string/-/string-3.2.7.tgz#76ae10f1e6e1fdaec7d0028a3f807d37a71bd2dd" + integrity sha512-D4OHBjrinH+PFZPvfCXvG28n2LSykWcJ7GIioQL+ok0LON15SdfoUssoHzzOUmVZLbRoREsQXVzA6r8JKsbP6A== + dependencies: + "@swc/helpers" "^0.5.0" + +"@isaacs/balanced-match@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz#3081dadbc3460661b751e7591d7faea5df39dd29" + integrity sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ== + +"@isaacs/brace-expansion@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz#4b3dabab7d8e75a429414a96bd67bf4c1d13e0f3" + integrity sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA== + dependencies: + "@isaacs/balanced-match" "^4.0.1" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0", "@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@microsoft/api-extractor-model@7.32.0": + version "7.32.0" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor-model/-/api-extractor-model-7.32.0.tgz#623147407e9607b1467e7b8d24c32fd313cdd6ad" + integrity sha512-QIVJSreb8fGGJy1Qx0yzGVXxvHJN1WXgkFNHFheVv1iBJNqgvp+xeT3ienJmRwXmPPc5Es/cxBrXtKZJR3i7iw== + dependencies: + "@microsoft/tsdoc" "~0.16.0" + "@microsoft/tsdoc-config" "~0.18.0" + "@rushstack/node-core-library" "5.18.0" + +"@microsoft/api-extractor@^7.50.1": + version "7.55.0" + resolved "https://registry.yarnpkg.com/@microsoft/api-extractor/-/api-extractor-7.55.0.tgz#1b3c3558111d9ba3c6e0adc948ca88d42906fa6e" + integrity sha512-TYc5OtAK/9E3HGgd2bIfSjQDYIwPc0dysf9rPiwXZGsq916I6W2oww9bhm1OxPOeg6rMfOX3PoroGd7oCryYog== + dependencies: + "@microsoft/api-extractor-model" "7.32.0" + "@microsoft/tsdoc" "~0.16.0" + "@microsoft/tsdoc-config" "~0.18.0" + "@rushstack/node-core-library" "5.18.0" + "@rushstack/rig-package" "0.6.0" + "@rushstack/terminal" "0.19.3" + "@rushstack/ts-command-line" "5.1.3" + diff "~8.0.2" + lodash "~4.17.15" + minimatch "10.0.3" + resolve "~1.22.1" + semver "~7.5.4" + source-map "~0.6.1" + typescript "5.8.2" + +"@microsoft/tsdoc-config@~0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc-config/-/tsdoc-config-0.18.0.tgz#02fd9924b888053ecbc3c0385a24532bf2106c98" + integrity sha512-8N/vClYyfOH+l4fLkkr9+myAoR6M7akc8ntBJ4DJdWH2b09uVfr71+LTMpNyG19fNqWDg8KEDZhx5wxuqHyGjw== + dependencies: + "@microsoft/tsdoc" "0.16.0" + ajv "~8.12.0" + jju "~1.4.0" + resolve "~1.22.2" + +"@microsoft/tsdoc@0.16.0", "@microsoft/tsdoc@~0.16.0": + version "0.16.0" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz#2249090633e04063176863a050c8f0808d2b6d2b" + integrity sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA== + +"@napi-rs/wasm-runtime@^0.2.11": + version "0.2.12" + resolved "https://registry.yarnpkg.com/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz#3e78a8b96e6c33a6c517e1894efbd5385a7cb6f2" + integrity sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ== + dependencies: + "@emnapi/core" "^1.4.3" + "@emnapi/runtime" "^1.4.3" + "@tybys/wasm-util" "^0.10.0" + +"@next/env@15.4.9": + version "15.4.9" + resolved "https://registry.yarnpkg.com/@next/env/-/env-15.4.9.tgz#5caeeaf5f20cf2bf5176444f13d087963159031f" + integrity sha512-OYR0RulK5phnbxxzcLE4/ECgfx1PL3EHrDbjyelJ7jauaO+/Qvj5gG8JPMltB51CygC2KrZ0aAfYLjPYjYY17A== + +"@next/eslint-plugin-next@15.1.7": + version "15.1.7" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-15.1.7.tgz#f8593c714f51ac6d443fb298584954d5def4392b" + integrity sha512-kRP7RjSxfTO13NE317ek3mSGzoZlI33nc/i5hs1KaWpK+egs85xg0DJ4p32QEiHnR0mVjuUfhRIun7awqfL7pQ== + dependencies: + fast-glob "3.3.1" + +"@next/swc-darwin-arm64@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.8.tgz#f5030219421079036720b5948ea9de9bee02ac34" + integrity sha512-Pf6zXp7yyQEn7sqMxur6+kYcywx5up1J849psyET7/8pG2gQTVMjU3NzgIt8SeEP5to3If/SaWmaA6H6ysBr1A== + +"@next/swc-darwin-x64@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.8.tgz#3fc796bd522aee30eff608448919e0ea1c1da7d1" + integrity sha512-xla6AOfz68a6kq3gRQccWEvFC/VRGJmA/QuSLENSO7CZX5WIEkSz7r1FdXUjtGCQ1c2M+ndUAH7opdfLK1PQbw== + +"@next/swc-linux-arm64-gnu@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.8.tgz#5c7bf6a0de49c2b4c21bc8bdb3b5e431dd922c7d" + integrity sha512-y3fmp+1Px/SJD+5ntve5QLZnGLycsxsVPkTzAc3zUiXYSOlTPqT8ynfmt6tt4fSo1tAhDPmryXpYKEAcoAPDJw== + +"@next/swc-linux-arm64-musl@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.8.tgz#94e47838715e68a696b33295f4389a60bd8af00a" + integrity sha512-DX/L8VHzrr1CfwaVjBQr3GWCqNNFgyWJbeQ10Lx/phzbQo3JNAxUok1DZ8JHRGcL6PgMRgj6HylnLNndxn4Z6A== + +"@next/swc-linux-x64-gnu@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.8.tgz#4f9656e8bf9f28dac1970d6ff95a245014646417" + integrity sha512-9fLAAXKAL3xEIFdKdzG5rUSvSiZTLLTCc6JKq1z04DR4zY7DbAPcRvNm3K1inVhTiQCs19ZRAgUerHiVKMZZIA== + +"@next/swc-linux-x64-musl@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.8.tgz#c5c64e18370f54f6474e58bb01b12594a4ecdde6" + integrity sha512-s45V7nfb5g7dbS7JK6XZDcapicVrMMvX2uYgOHP16QuKH/JA285oy6HcxlKqwUNaFY/UC6EvQ8QZUOo19cBKSA== + +"@next/swc-win32-arm64-msvc@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.8.tgz#722d18ed569bee9e4a6651acdc756f9633cbee1f" + integrity sha512-KjgeQyOAq7t/HzAJcWPGA8X+4WY03uSCZ2Ekk98S9OgCFsb6lfBE3dbUzUuEQAN2THbwYgFfxX2yFTCMm8Kehw== + +"@next/swc-win32-x64-msvc@15.4.8": + version "15.4.8" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.8.tgz#a29a53cd262ec5093b9ac24a5fd5e4540ec64eb4" + integrity sha512-Exsmf/+42fWVnLMaZHzshukTBxZrSwuuLKFvqhGHJ+mC1AokqieLY/XzAl3jc/CqhXLqLY3RRjkKJ9YnLPcRWg== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + +"@openfun/cunningham-react@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@openfun/cunningham-react/-/cunningham-react-4.0.0.tgz#5d273c72a2ced76cf060931b546238b7ee75c6ec" + integrity sha512-2JgIRDl2UE/PMcOrjjfxbhFRwEwF7JFAaPoN/Xjq+sOYHP6WasRxFRrkwhnuZ5ZU7lOpzaAFyPtkawoBF6GsEQ== + dependencies: + "@fontsource-variable/roboto-flex" "5.2.5" + "@fontsource/material-icons-outlined" "5.2.5" + "@internationalized/date" "3.8.0" + "@openfun/cunningham-tokens" "*" + "@react-aria/calendar" "3.8.0" + "@react-aria/datepicker" "3.14.2" + "@react-aria/i18n" "3.12.8" + "@react-stately/calendar" "3.8.0" + "@react-stately/datepicker" "3.14.0" + "@tanstack/react-table" "8.21.3" + "@types/react-modal" "3.16.3" + chromatic "11.28.2" + classnames "2.5.1" + downshift "9.0.9" + react-aria "3.39.0" + react-aria-components "1.8.0" + react-modal "3.16.3" + react-stately "3.37.0" + +"@openfun/cunningham-tokens@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@openfun/cunningham-tokens/-/cunningham-tokens-3.0.0.tgz#2346ebcb7d18a35cbbb1c4f4c501f238173a3c8c" + integrity sha512-YMLLL7CaQA1+kuSVxf3UgXNjdyeX6Dj2Kdlz/9+lX2ePm51rPxZsEGXWeUVafNLFH+T/zpsajiEzgJ9mBEJd5w== + dependencies: + chalk "4.1.2" + commander "13.1.0" + deepmerge "4.3.1" + figlet "1.8.1" + ts-node "10.9.2" + +"@parcel/watcher-android-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.1.tgz#507f836d7e2042f798c7d07ad19c3546f9848ac1" + integrity sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA== + +"@parcel/watcher-darwin-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.1.tgz#3d26dce38de6590ef79c47ec2c55793c06ad4f67" + integrity sha512-eAzPv5osDmZyBhou8PoF4i6RQXAfeKL9tjb3QzYuccXFMQU0ruIc/POh30ePnaOyD1UXdlKguHBmsTs53tVoPw== + +"@parcel/watcher-darwin-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.1.tgz#99f3af3869069ccf774e4ddfccf7e64fd2311ef8" + integrity sha512-1ZXDthrnNmwv10A0/3AJNZ9JGlzrF82i3gNQcWOzd7nJ8aj+ILyW1MTxVk35Db0u91oD5Nlk9MBiujMlwmeXZg== + +"@parcel/watcher-freebsd-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.1.tgz#14d6857741a9f51dfe51d5b08b7c8afdbc73ad9b" + integrity sha512-SI4eljM7Flp9yPuKi8W0ird8TI/JK6CSxju3NojVI6BjHsTyK7zxA9urjVjEKJ5MBYC+bLmMcbAWlZ+rFkLpJQ== + +"@parcel/watcher-linux-arm-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.1.tgz#43c3246d6892381db473bb4f663229ad20b609a1" + integrity sha512-RCdZlEyTs8geyBkkcnPWvtXLY44BCeZKmGYRtSgtwwnHR4dxfHRG3gR99XdMEdQ7KeiDdasJwwvNSF5jKtDwdA== + +"@parcel/watcher-linux-arm-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.1.tgz#663750f7090bb6278d2210de643eb8a3f780d08e" + integrity sha512-6E+m/Mm1t1yhB8X412stiKFG3XykmgdIOqhjWj+VL8oHkKABfu/gjFj8DvLrYVHSBNC+/u5PeNrujiSQ1zwd1Q== + +"@parcel/watcher-linux-arm64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.1.tgz#ba60e1f56977f7e47cd7e31ad65d15fdcbd07e30" + integrity sha512-LrGp+f02yU3BN9A+DGuY3v3bmnFUggAITBGriZHUREfNEzZh/GO06FF5u2kx8x+GBEUYfyTGamol4j3m9ANe8w== + +"@parcel/watcher-linux-arm64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.1.tgz#f7fbcdff2f04c526f96eac01f97419a6a99855d2" + integrity sha512-cFOjABi92pMYRXS7AcQv9/M1YuKRw8SZniCDw0ssQb/noPkRzA+HBDkwmyOJYp5wXcsTrhxO0zq1U11cK9jsFg== + +"@parcel/watcher-linux-x64-glibc@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz#4d2ea0f633eb1917d83d483392ce6181b6a92e4e" + integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A== + +"@parcel/watcher-linux-x64-musl@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz#277b346b05db54f55657301dd77bdf99d63606ee" + integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg== + +"@parcel/watcher-win32-arm64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.1.tgz#7e9e02a26784d47503de1d10e8eab6cceb524243" + integrity sha512-RFzklRvmc3PkjKjry3hLF9wD7ppR4AKcWNzH7kXR7GUe0Igb3Nz8fyPwtZCSquGrhU5HhUNDr/mKBqj7tqA2Vw== + +"@parcel/watcher-win32-ia32@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.1.tgz#2d0f94fa59a873cdc584bf7f6b1dc628ddf976e6" + integrity sha512-c2KkcVN+NJmuA7CGlaGD1qJh1cLfDnQsHjE89E60vUEMlqduHGCdCLJCID5geFVM0dOtA3ZiIO8BoEQmzQVfpQ== + +"@parcel/watcher-win32-x64@2.5.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.1.tgz#ae52693259664ba6f2228fa61d7ee44b64ea0947" + integrity sha512-9lHBdJITeNR++EvSQVUcaZoWupyHfXe1jZvGZ06O/5MflPcuPLtEphScIBL+AiCWBO46tDSHzWyD0uDmmZqsgA== + +"@parcel/watcher@^2.4.1": + version "2.5.1" + resolved "https://registry.yarnpkg.com/@parcel/watcher/-/watcher-2.5.1.tgz#342507a9cfaaf172479a882309def1e991fb1200" + integrity sha512-dfUnCxiN9H4ap84DvD2ubjw+3vUNpstxa0TneY/Paat8a3R4uQZDLSvWjmznAY/DoahqTHl9V46HF/Zs3F29pg== + 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" + +"@playwright/test@1.56.1": + version "1.56.1" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.56.1.tgz#6e3bf3d0c90c5cf94bf64bdb56fd15a805c8bd3f" + integrity sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg== + dependencies: + playwright "1.56.1" + +"@posthog/core@1.5.2": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@posthog/core/-/core-1.5.2.tgz#06f1277c5ac9a3d5a17bc3800172a392e594f44c" + integrity sha512-iedUP3EnOPPxTA2VaIrsrd29lSZnUV+ZrMnvY56timRVeZAXoYCkmjfIs3KBAsF8OUT5h1GXLSkoQdrV0r31OQ== + dependencies: + cross-spawn "^7.0.6" + +"@radix-ui/primitive@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.3.tgz#e2dbc13bdc5e4168f4334f75832d7bdd3e2de5ba" + integrity sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg== + +"@radix-ui/react-compose-refs@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz#a2c4c47af6337048ee78ff6dc0d090b390d2bb30" + integrity sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg== + +"@radix-ui/react-context@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.2.tgz#61628ef269a433382c364f6f1e3788a6dc213a36" + integrity sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA== + +"@radix-ui/react-dialog@^1.1.2": + version "1.1.15" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz#1de3d7a7e9a17a9874d29c07f5940a18a119b632" + integrity sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw== + dependencies: + "@radix-ui/primitive" "1.1.3" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-context" "1.1.2" + "@radix-ui/react-dismissable-layer" "1.1.11" + "@radix-ui/react-focus-guards" "1.1.3" + "@radix-ui/react-focus-scope" "1.1.7" + "@radix-ui/react-id" "1.1.1" + "@radix-ui/react-portal" "1.1.9" + "@radix-ui/react-presence" "1.1.5" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-slot" "1.2.3" + "@radix-ui/react-use-controllable-state" "1.2.2" + aria-hidden "^1.2.4" + react-remove-scroll "^2.6.3" + +"@radix-ui/react-dismissable-layer@1.1.11": + version "1.1.11" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz#e33ab6f6bdaa00f8f7327c408d9f631376b88b37" + integrity sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg== + dependencies: + "@radix-ui/primitive" "1.1.3" + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + "@radix-ui/react-use-escape-keydown" "1.1.1" + +"@radix-ui/react-focus-guards@1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz#2a5669e464ad5fde9f86d22f7fdc17781a4dfa7f" + integrity sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw== + +"@radix-ui/react-focus-scope@1.1.7": + version "1.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz#dfe76fc103537d80bf42723a183773fd07bfb58d" + integrity sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-callback-ref" "1.1.1" + +"@radix-ui/react-id@1.1.1", "@radix-ui/react-id@^1.1.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-1.1.1.tgz#1404002e79a03fe062b7e3864aa01e24bd1471f7" + integrity sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-portal@1.1.9": + version "1.1.9" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-1.1.9.tgz#14c3649fe48ec474ac51ed9f2b9f5da4d91c4472" + integrity sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ== + dependencies: + "@radix-ui/react-primitive" "2.1.3" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-presence@1.1.5": + version "1.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-1.1.5.tgz#5d8f28ac316c32f078afce2996839250c10693db" + integrity sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-primitive@2.1.3": + version "2.1.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz#db9b8bcff49e01be510ad79893fb0e4cda50f1bc" + integrity sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ== + dependencies: + "@radix-ui/react-slot" "1.2.3" + +"@radix-ui/react-primitive@^2.0.0": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz#2626ea309ebd63bf5767d3e7fc4081f81b993df0" + integrity sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg== + dependencies: + "@radix-ui/react-slot" "1.2.4" + +"@radix-ui/react-slot@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.3.tgz#502d6e354fc847d4169c3bc5f189de777f68cfe1" + integrity sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + +"@radix-ui/react-slot@1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.2.4.tgz#63c0ba05fdf90cc49076b94029c852d7bac1fb83" + integrity sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA== + dependencies: + "@radix-ui/react-compose-refs" "1.1.2" + +"@radix-ui/react-use-callback-ref@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz#62a4dba8b3255fdc5cc7787faeac1c6e4cc58d40" + integrity sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg== + +"@radix-ui/react-use-controllable-state@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz#905793405de57d61a439f4afebbb17d0645f3190" + integrity sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg== + dependencies: + "@radix-ui/react-use-effect-event" "0.0.2" + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-effect-event@0.0.2": + version "0.0.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz#090cf30d00a4c7632a15548512e9152217593907" + integrity sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA== + dependencies: + "@radix-ui/react-use-layout-effect" "1.1.1" + +"@radix-ui/react-use-escape-keydown@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz#b3fed9bbea366a118f40427ac40500aa1423cc29" + integrity sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g== + dependencies: + "@radix-ui/react-use-callback-ref" "1.1.1" + +"@radix-ui/react-use-layout-effect@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz#0c4230a9eed49d4589c967e2d9c0d9d60a23971e" + integrity sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ== + +"@react-aria/autocomplete@3.0.0-beta.2": + version "3.0.0-beta.2" + resolved "https://registry.yarnpkg.com/@react-aria/autocomplete/-/autocomplete-3.0.0-beta.2.tgz#61fc21cde05206e9a90f32378f25d13f5424366c" + integrity sha512-oxsFCIGj5yooQkZzdqjvsdfr9fOlmAq4v6njIOAyQFsta3H0yQiv+YU3XnrnCBxVX+Mz/mZtZgfhAA9JBDukHg== + dependencies: + "@react-aria/combobox" "^3.12.2" + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/listbox" "^3.14.3" + "@react-aria/searchfield" "^3.8.3" + "@react-aria/textfield" "^3.17.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/autocomplete" "3.0.0-beta.1" + "@react-stately/combobox" "^3.10.4" + "@react-types/autocomplete" "3.0.0-alpha.30" + "@react-types/button" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/breadcrumbs@^3.5.23", "@react-aria/breadcrumbs@^3.5.29": + version "3.5.29" + resolved "https://registry.yarnpkg.com/@react-aria/breadcrumbs/-/breadcrumbs-3.5.29.tgz#bfc1e953eccd7393bd457f1c9698a928142f0fc7" + integrity sha512-rKS0dryllaZJqrr3f/EAf2liz8CBEfmL5XACj+Z1TAig6GIYe1QuA3BtkX0cV9OkMugXdX8e3cbA7nD10ORRqg== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/link" "^3.8.6" + "@react-aria/utils" "^3.31.0" + "@react-types/breadcrumbs" "^3.7.17" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/button@^3.13.0", "@react-aria/button@^3.14.2": + version "3.14.2" + resolved "https://registry.yarnpkg.com/@react-aria/button/-/button-3.14.2.tgz#9dcd2fa53e7968a563b4898ace3360c85ccc22f5" + integrity sha512-VbLIA+Kd6f/MDjd+TJBUg2+vNDw66pnvsj2E4RLomjI9dfBuN7d+Yo2UnsqKVyhePjCUZ6xxa2yDuD63IOSIYA== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/toolbar" "3.0.0-beta.21" + "@react-aria/utils" "^3.31.0" + "@react-stately/toggle" "^3.9.2" + "@react-types/button" "^3.14.1" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/calendar@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.8.0.tgz#8f210d2ecfd89a8020f5568fdf2014a8e6c62a46" + integrity sha512-9vms/fWjJPZkJcMxciwWWOjGy/Q0nqI6FV0pYbMZbqepkzglEaVd98kl506r/4hLhWKwLdTfqCgbntRecj8jBg== + dependencies: + "@internationalized/date" "^3.8.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/utils" "^3.28.2" + "@react-stately/calendar" "^3.8.0" + "@react-types/button" "^3.12.0" + "@react-types/calendar" "^3.7.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/calendar@^3.8.0", "@react-aria/calendar@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-aria/calendar/-/calendar-3.9.2.tgz#4b6e428ee3fb81f5729cb80193b9d4ba9b26d5f1" + integrity sha512-uSLxLgOPRnEU4Jg59lAhUVA+uDx/55NBg4lpfsP2ynazyiJ5LCXmYceJi+VuOqMml7d9W0dB87OldOeLdIxYVA== + dependencies: + "@internationalized/date" "^3.10.0" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.31.0" + "@react-stately/calendar" "^3.9.0" + "@react-types/button" "^3.14.1" + "@react-types/calendar" "^3.8.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/checkbox@^3.15.4", "@react-aria/checkbox@^3.16.2": + version "3.16.2" + resolved "https://registry.yarnpkg.com/@react-aria/checkbox/-/checkbox-3.16.2.tgz#b1a3310d327826fe354625c332f3b80acb025a39" + integrity sha512-29Mj9ZqXioJ0bcMnNGooHztnTau5pikZqX3qCRj5bYR3by/ZFFavYoMroh9F7s/MbFm/tsKX+Sf02lYFEdXRjA== + dependencies: + "@react-aria/form" "^3.1.2" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/toggle" "^3.12.2" + "@react-aria/utils" "^3.31.0" + "@react-stately/checkbox" "^3.7.2" + "@react-stately/form" "^3.2.2" + "@react-stately/toggle" "^3.9.2" + "@react-types/checkbox" "^3.10.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/collections@3.0.0-rc.0": + version "3.0.0-rc.0" + resolved "https://registry.yarnpkg.com/@react-aria/collections/-/collections-3.0.0-rc.0.tgz#d0a906f4a4582a91b6ad866a58fbe2ef1713b15e" + integrity sha512-WcRcE3wKtbprOJlBaMbdYS5Suu2KIGq1gVT2fLXVbmDY0CjGemqp2m5aDblQOO8pxvsAqHV8pyznkhANTnK1CQ== + dependencies: + "@react-aria/interactions" "^3.25.0" + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.4.0" + +"@react-aria/color@^3.0.6", "@react-aria/color@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-aria/color/-/color-3.1.2.tgz#9ee2a86e4cf4622ca8ff78bddd34a2bf1bdcdd34" + integrity sha512-jCC+Q7rAQGLQBkHjkPAeDuGYuMbc4neifjlNRiyZ9as1z4gg63H8MteoWYYk6K4vCKKxSixgt8MfI29XWMOWPQ== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/numberfield" "^3.12.2" + "@react-aria/slider" "^3.8.2" + "@react-aria/spinbutton" "^3.6.19" + "@react-aria/textfield" "^3.18.2" + "@react-aria/utils" "^3.31.0" + "@react-aria/visually-hidden" "^3.8.28" + "@react-stately/color" "^3.9.2" + "@react-stately/form" "^3.2.2" + "@react-types/color" "^3.1.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/combobox@^3.12.2", "@react-aria/combobox@^3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@react-aria/combobox/-/combobox-3.14.0.tgz#1e6c55a319d367d6a0a9e19f2bd68d3a9a0c8b9a" + integrity sha512-z4ro0Hma//p4nL2IJx5iUa7NwxeXbzSoZ0se5uTYjG1rUUMszg+wqQh/AQoL+eiULn7rs18JY9wwNbVIkRNKWA== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/listbox" "^3.15.0" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/menu" "^3.19.3" + "@react-aria/overlays" "^3.30.0" + "@react-aria/selection" "^3.26.0" + "@react-aria/textfield" "^3.18.2" + "@react-aria/utils" "^3.31.0" + "@react-stately/collections" "^3.12.8" + "@react-stately/combobox" "^3.12.0" + "@react-stately/form" "^3.2.2" + "@react-types/button" "^3.14.1" + "@react-types/combobox" "^3.13.9" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/datepicker@3.14.2": + version "3.14.2" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.14.2.tgz#db1efa94edc86b57950cf32cbfd252b206653fab" + integrity sha512-O7fdzcqIJ7i/+8SGYvx4tloTZgK4Ws8OChdbFcd2rZoRPqxM50M6J+Ota8hTet2wIhojUXnM3x2na3EvoucBXA== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/number" "^3.6.1" + "@internationalized/string" "^3.2.6" + "@react-aria/focus" "^3.20.2" + "@react-aria/form" "^3.0.15" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/spinbutton" "^3.6.14" + "@react-aria/utils" "^3.28.2" + "@react-stately/datepicker" "^3.14.0" + "@react-stately/form" "^3.1.3" + "@react-types/button" "^3.12.0" + "@react-types/calendar" "^3.7.0" + "@react-types/datepicker" "^3.12.0" + "@react-types/dialog" "^3.5.17" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/datepicker@^3.14.2", "@react-aria/datepicker@^3.15.2": + version "3.15.2" + resolved "https://registry.yarnpkg.com/@react-aria/datepicker/-/datepicker-3.15.2.tgz#22bca8cfdd00e32a42f8e53b35e5ba7e886f047d" + integrity sha512-th078hyNqPf4P2K10su/y32zPDjs3lOYVdHvsL9/+5K1dnTvLHCK5vgUyLuyn8FchhF7cmHV49D+LZVv65PEpQ== + dependencies: + "@internationalized/date" "^3.10.0" + "@internationalized/number" "^3.6.5" + "@internationalized/string" "^3.2.7" + "@react-aria/focus" "^3.21.2" + "@react-aria/form" "^3.1.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/spinbutton" "^3.6.19" + "@react-aria/utils" "^3.31.0" + "@react-stately/datepicker" "^3.15.2" + "@react-stately/form" "^3.2.2" + "@react-types/button" "^3.14.1" + "@react-types/calendar" "^3.8.0" + "@react-types/datepicker" "^3.13.2" + "@react-types/dialog" "^3.5.22" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/dialog@^3.5.24", "@react-aria/dialog@^3.5.31": + version "3.5.31" + resolved "https://registry.yarnpkg.com/@react-aria/dialog/-/dialog-3.5.31.tgz#1c1682a89dd6a4c6bc7bb0e58ea78eb6f2750a65" + integrity sha512-inxQMyrzX0UBW9Mhraq0nZ4HjHdygQvllzloT1E/RlDd61lr3RbmJR6pLsrbKOTtSvDIBJpCso1xEdHCFNmA0Q== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/overlays" "^3.30.0" + "@react-aria/utils" "^3.31.0" + "@react-types/dialog" "^3.5.22" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/disclosure@^3.0.4", "@react-aria/disclosure@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@react-aria/disclosure/-/disclosure-3.1.0.tgz#c08a0f9696fa80ca69de78f37c8bf0b65a7a9397" + integrity sha512-5996BeBpnj+yKXYysz+UuhFQxGFPvaZZ3zNBd052wz/i+TVFVGSqqYJ6cwZyO1AfBR8zOT0ZIiK4EC3ETwSvtQ== + dependencies: + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.31.0" + "@react-stately/disclosure" "^3.0.8" + "@react-types/button" "^3.14.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/dnd@^3.11.3", "@react-aria/dnd@^3.9.2": + version "3.11.3" + resolved "https://registry.yarnpkg.com/@react-aria/dnd/-/dnd-3.11.3.tgz#438b4603ef9b2560775ea02b64ea3dcdf15bf474" + integrity sha512-MyTziciik1Owz3rqDghu0K3ZtTFvmj/R2ZsLDwbU9N4hKqGX/BKnrI8SytTn8RDqVv5LmA/GhApLngiupTAsXw== + dependencies: + "@internationalized/string" "^3.2.7" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/overlays" "^3.30.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/collections" "^3.12.8" + "@react-stately/dnd" "^3.7.1" + "@react-types/button" "^3.14.1" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/focus@^3.20.2", "@react-aria/focus@^3.21.2": + version "3.21.2" + resolved "https://registry.yarnpkg.com/@react-aria/focus/-/focus-3.21.2.tgz#3ce90450c3ee69f11c0647b4717c26d10941231c" + integrity sha512-JWaCR7wJVggj+ldmM/cb/DXFg47CXR55lznJhZBh4XVqJjMKwaOOqpT5vNN7kpC1wUpXicGNuDnJDN1S/+6dhQ== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + clsx "^2.0.0" + +"@react-aria/form@^3.0.15", "@react-aria/form@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-aria/form/-/form-3.1.2.tgz#e0aeb608d309594a59f12a7b05eb7374f2033a07" + integrity sha512-R3i7L7Ci61PqZQvOrnL9xJeWEbh28UkTVgkj72EvBBn39y4h7ReH++0stv7rRs8p5ozETSKezBbGfu4UsBewWw== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-stately/form" "^3.2.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/grid@^3.14.5": + version "3.14.5" + resolved "https://registry.yarnpkg.com/@react-aria/grid/-/grid-3.14.5.tgz#fccd1e3b64cdad7b17aff0dada6da64df0cd1d8c" + integrity sha512-XHw6rgjlTqc85e3zjsWo3U0EVwjN5MOYtrolCKc/lc2ItNdcY3OlMhpsU9+6jHwg/U3VCSWkGvwAz9hg7krd8Q== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/collections" "^3.12.8" + "@react-stately/grid" "^3.11.6" + "@react-stately/selection" "^3.20.6" + "@react-types/checkbox" "^3.10.2" + "@react-types/grid" "^3.3.6" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/gridlist@^3.12.0", "@react-aria/gridlist@^3.14.1": + version "3.14.1" + resolved "https://registry.yarnpkg.com/@react-aria/gridlist/-/gridlist-3.14.1.tgz#4aa636ad1342f859dc5ce1a350211535ae5ae424" + integrity sha512-keS03Am07aOn7RuNaRsMOyh0jscyhDn95asCVy4lxhl9A9TFk1Jw0o2L6q6cWRj1gFiKeacj/otG5H8ZKQQ2Wg== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/grid" "^3.14.5" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/list" "^3.13.1" + "@react-stately/tree" "^3.9.3" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/i18n@3.12.8": + version "3.12.8" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.8.tgz#43d534f04d3bfdef674ba94527cf7532875d8fc8" + integrity sha512-V/Nau9WuwTwxfFffQL4URyKyY2HhRlu9zmzkF2Hw/j5KmEQemD+9jfaLueG2CJu85lYL06JrZXUdnhZgKnqMkA== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/message" "^3.1.7" + "@internationalized/number" "^3.6.1" + "@internationalized/string" "^3.2.6" + "@react-aria/ssr" "^3.9.8" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/i18n@^3.12.13", "@react-aria/i18n@^3.12.8": + version "3.12.13" + resolved "https://registry.yarnpkg.com/@react-aria/i18n/-/i18n-3.12.13.tgz#7c920d131cd07d4d5af21bd33ea7a5da0ce2ad11" + integrity sha512-YTM2BPg0v1RvmP8keHenJBmlx8FXUKsdYIEX7x6QWRd1hKlcDwphfjzvt0InX9wiLiPHsT5EoBTpuUk8SXc0Mg== + dependencies: + "@internationalized/date" "^3.10.0" + "@internationalized/message" "^3.1.8" + "@internationalized/number" "^3.6.5" + "@internationalized/string" "^3.2.7" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/interactions@^3.25.0", "@react-aria/interactions@^3.25.6": + version "3.25.6" + resolved "https://registry.yarnpkg.com/@react-aria/interactions/-/interactions-3.25.6.tgz#6fdf287337c5e4285045c35cf94b2ec8ae3b3a49" + integrity sha512-5UgwZmohpixwNMVkMvn9K1ceJe6TzlRlAfuYoQDUuOkk62/JVJNDLAPKIf5YMRc7d2B0rmfgaZLMtbREb0Zvkw== + dependencies: + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.31.0" + "@react-stately/flags" "^3.1.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/label@^3.7.17", "@react-aria/label@^3.7.22": + version "3.7.22" + resolved "https://registry.yarnpkg.com/@react-aria/label/-/label-3.7.22.tgz#13fbf1d568c37becca4652e5c5d0b490c29e5e52" + integrity sha512-jLquJeA5ZNqDT64UpTc9XJ7kQYltUlNcgxZ37/v4mHe0UZ7QohCKdKQhXHONb0h2jjNUpp2HOZI8J9++jOpzxA== + dependencies: + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/landmark@^3.0.2", "@react-aria/landmark@^3.0.7": + version "3.0.7" + resolved "https://registry.yarnpkg.com/@react-aria/landmark/-/landmark-3.0.7.tgz#6ffc06c870018f6ead456f6f67cccebd655910f0" + integrity sha512-t8c610b8hPLS6Vwv+rbuSyljZosI1s5+Tosfa0Fk4q7d+Ex6Yj7hLfUFy59GxZAufhUYfGX396fT0gPqAbU1tg== + dependencies: + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.4.0" + +"@react-aria/link@^3.8.0", "@react-aria/link@^3.8.6": + version "3.8.6" + resolved "https://registry.yarnpkg.com/@react-aria/link/-/link-3.8.6.tgz#522c246b9fcf62fbe75f9c07d056d6b984523143" + integrity sha512-7F7UDJnwbU9IjfoAdl6f3Hho5/WB7rwcydUOjUux0p7YVWh/fTjIFjfAGyIir7MJhPapun1D0t97QQ3+8jXVcg== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-types/link" "^3.6.5" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/listbox@^3.14.3", "@react-aria/listbox@^3.15.0": + version "3.15.0" + resolved "https://registry.yarnpkg.com/@react-aria/listbox/-/listbox-3.15.0.tgz#4218e24c20ec68069f51175c57fa2bf55b1acc46" + integrity sha512-Ub1Wu79R9sgxM7h4HeEdjOgOKDHwduvYcnDqsSddGXgpkL8ADjsy2YUQ0hHY5VnzA4BxK36bLp4mzSna8Qvj1w== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/collections" "^3.12.8" + "@react-stately/list" "^3.13.1" + "@react-types/listbox" "^3.7.4" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/live-announcer@^3.4.2", "@react-aria/live-announcer@^3.4.4": + version "3.4.4" + resolved "https://registry.yarnpkg.com/@react-aria/live-announcer/-/live-announcer-3.4.4.tgz#0e6533940222208b323b71d56ac8e115b2121e6a" + integrity sha512-PTTBIjNRnrdJOIRTDGNifY2d//kA7GUAwRFJNOEwSNG4FW+Bq9awqLiflw0JkpyB0VNIwou6lqKPHZVLsGWOXA== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-aria/menu@^3.18.2", "@react-aria/menu@^3.19.3": + version "3.19.3" + resolved "https://registry.yarnpkg.com/@react-aria/menu/-/menu-3.19.3.tgz#65a6dc14b27648be611bf28ab4bbcd2823b612a8" + integrity sha512-52fh8y8b2776R2VrfZPpUBJYC9oTP7XDy+zZuZTxPEd7Ywk0JNUl5F92y6ru22yPkS13sdhrNM/Op+V/KulmAg== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/overlays" "^3.30.0" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/collections" "^3.12.8" + "@react-stately/menu" "^3.9.8" + "@react-stately/selection" "^3.20.6" + "@react-stately/tree" "^3.9.3" + "@react-types/button" "^3.14.1" + "@react-types/menu" "^3.10.5" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/meter@^3.4.22", "@react-aria/meter@^3.4.27": + version "3.4.27" + resolved "https://registry.yarnpkg.com/@react-aria/meter/-/meter-3.4.27.tgz#01cf9bbd12f05bd0515e048960690b017b0b9dd2" + integrity sha512-andOOdJkgRJF9vBi5VWRmFodK+GT+5X1lLeNUmb4qOX8/MVfX/RbK72LDeIhd7xC7rSCFHj3WvZ198rK4q0k3w== + dependencies: + "@react-aria/progress" "^3.4.27" + "@react-types/meter" "^3.4.13" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/numberfield@^3.11.13", "@react-aria/numberfield@^3.12.2": + version "3.12.2" + resolved "https://registry.yarnpkg.com/@react-aria/numberfield/-/numberfield-3.12.2.tgz#c219ecfba2076865e891cb2435c6bad558d6eabf" + integrity sha512-M2b+z0HIXiXpGAWOQkO2kpIjaLNUXJ5Q3/GMa3Fkr+B1piFX0VuOynYrtddKVrmXCe+r5t+XcGb0KS29uqv7nQ== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/spinbutton" "^3.6.19" + "@react-aria/textfield" "^3.18.2" + "@react-aria/utils" "^3.31.0" + "@react-stately/form" "^3.2.2" + "@react-stately/numberfield" "^3.10.2" + "@react-types/button" "^3.14.1" + "@react-types/numberfield" "^3.8.15" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/overlays@^3.27.0", "@react-aria/overlays@^3.30.0": + version "3.30.0" + resolved "https://registry.yarnpkg.com/@react-aria/overlays/-/overlays-3.30.0.tgz#e19f804c7fb9d99b25e33230cc3c155ed0b3cefb" + integrity sha512-UpjqSjYZx5FAhceWCRVsW6fX1sEwya1fQ/TKkL53FAlLFR8QKuoKqFlmiL43YUFTcGK3UdEOy3cWTleLQwdSmQ== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/ssr" "^3.9.10" + "@react-aria/utils" "^3.31.0" + "@react-aria/visually-hidden" "^3.8.28" + "@react-stately/overlays" "^3.6.20" + "@react-types/button" "^3.14.1" + "@react-types/overlays" "^3.9.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/progress@^3.4.22", "@react-aria/progress@^3.4.27": + version "3.4.27" + resolved "https://registry.yarnpkg.com/@react-aria/progress/-/progress-3.4.27.tgz#bdc968f133ddd33e5feaf2903d43aa34435dad51" + integrity sha512-0OA1shs1575g1zmO8+rWozdbTnxThFFhOfuoL1m7UV5Dley6FHpueoKB1ECv7B+Qm4dQt6DoEqLg7wsbbQDhmg== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/label" "^3.7.22" + "@react-aria/utils" "^3.31.0" + "@react-types/progress" "^3.5.16" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/radio@^3.11.2", "@react-aria/radio@^3.12.2": + version "3.12.2" + resolved "https://registry.yarnpkg.com/@react-aria/radio/-/radio-3.12.2.tgz#48ae0e9ba93e5c29e998fa3b64155a324a87f63e" + integrity sha512-I11f6I90neCh56rT/6ieAs3XyDKvEfbj/QmbU5cX3p+SJpRRPN0vxQi5D1hkh0uxDpeClxygSr31NmZsd4sqfg== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/form" "^3.1.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/utils" "^3.31.0" + "@react-stately/radio" "^3.11.2" + "@react-types/radio" "^3.9.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/searchfield@^3.8.3", "@react-aria/searchfield@^3.8.9": + version "3.8.9" + resolved "https://registry.yarnpkg.com/@react-aria/searchfield/-/searchfield-3.8.9.tgz#faa82c976bf3ef6c678bf9a2f9ae9bea9d4d3096" + integrity sha512-Yt2pj8Wb5/XsUr2T0DQqFv+DlFpzzWIWnNr9cJATUcWV/xw6ok7YFEg9+7EHtBmsCQxFFJtock1QfZzBw6qLtQ== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/textfield" "^3.18.2" + "@react-aria/utils" "^3.31.0" + "@react-stately/searchfield" "^3.5.16" + "@react-types/button" "^3.14.1" + "@react-types/searchfield" "^3.6.6" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/select@^3.15.4", "@react-aria/select@^3.17.0": + version "3.17.0" + resolved "https://registry.yarnpkg.com/@react-aria/select/-/select-3.17.0.tgz#d96933daca43939f4d59518f843c87a4f600426f" + integrity sha512-q5ZuyAn5jSOeI0Ys99951TaGcF4O7u1SSBVxPMwVVXOU8ZhToCNx+WG3n/JDYHEjqdo7sbsVRaPA7LkBzBGf5w== + dependencies: + "@react-aria/form" "^3.1.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/listbox" "^3.15.0" + "@react-aria/menu" "^3.19.3" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-aria/visually-hidden" "^3.8.28" + "@react-stately/select" "^3.8.0" + "@react-types/button" "^3.14.1" + "@react-types/select" "^3.11.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/selection@^3.24.0", "@react-aria/selection@^3.26.0": + version "3.26.0" + resolved "https://registry.yarnpkg.com/@react-aria/selection/-/selection-3.26.0.tgz#dc5906aa732b0dbd54d26dd6a5f1dc793055e29c" + integrity sha512-ZBH3EfWZ+RfhTj01dH8L17uT7iNbXWS8u77/fUpHgtrm0pwNVhx0TYVnLU1YpazQ/3WVpvWhmBB8sWwD1FlD/g== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-stately/selection" "^3.20.6" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/separator@^3.4.13", "@react-aria/separator@^3.4.8": + version "3.4.13" + resolved "https://registry.yarnpkg.com/@react-aria/separator/-/separator-3.4.13.tgz#6eea332c68b67d1081f4d8c2af8198c6bc46bfb4" + integrity sha512-0NlcrdBfQbcjWEXdHl3+uSY1272n2ljT1gWL2RIf6aQsQWTZ0gz0rTgRHy0MTXN+y+tICItUERJT4vmTLtIzVg== + dependencies: + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/slider@^3.7.18", "@react-aria/slider@^3.8.2": + version "3.8.2" + resolved "https://registry.yarnpkg.com/@react-aria/slider/-/slider-3.8.2.tgz#a075205b06fa714733e3aabfdbc63d11f5c67be7" + integrity sha512-6KyUGaVzRE4xAz1LKHbNh1q5wzxe58pdTHFSnxNe6nk1SCoHw7NfI4h2s2m6LgJ0megFxsT0Ir8aHaFyyxmbgg== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/utils" "^3.31.0" + "@react-stately/slider" "^3.7.2" + "@react-types/shared" "^3.32.1" + "@react-types/slider" "^3.8.2" + "@swc/helpers" "^0.5.0" + +"@react-aria/spinbutton@^3.6.14", "@react-aria/spinbutton@^3.6.19": + version "3.6.19" + resolved "https://registry.yarnpkg.com/@react-aria/spinbutton/-/spinbutton-3.6.19.tgz#fd0253b95b88e9fb12ff406b722b4fd1e1c8c836" + integrity sha512-xOIXegDpts9t3RSHdIN0iYQpdts0FZ3LbpYJIYVvdEHo9OpDS+ElnDzCGtwZLguvZlwc5s1LAKuKopDUsAEMkw== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.31.0" + "@react-types/button" "^3.14.1" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/ssr@^3.9.10", "@react-aria/ssr@^3.9.8": + version "3.9.10" + resolved "https://registry.yarnpkg.com/@react-aria/ssr/-/ssr-3.9.10.tgz#7fdc09e811944ce0df1d7e713de1449abd7435e6" + integrity sha512-hvTm77Pf+pMBhuBm760Li0BVIO38jv1IBws1xFm1NoL26PU+fe+FMW5+VZWyANR6nYL65joaJKZqOdTQMkO9IQ== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-aria/switch@^3.7.2", "@react-aria/switch@^3.7.8": + version "3.7.8" + resolved "https://registry.yarnpkg.com/@react-aria/switch/-/switch-3.7.8.tgz#e0a14f5eeda6017ae4d2b1cd236270d45c03e5ca" + integrity sha512-AfsUq1/YiuoprhcBUD9vDPyWaigAwctQNW1fMb8dROL+i/12B+Zekj8Ml+jbU69/kIVtfL0Jl7/0Bo9KK3X0xQ== + dependencies: + "@react-aria/toggle" "^3.12.2" + "@react-stately/toggle" "^3.9.2" + "@react-types/shared" "^3.32.1" + "@react-types/switch" "^3.5.15" + "@swc/helpers" "^0.5.0" + +"@react-aria/table@^3.17.2", "@react-aria/table@^3.17.8": + version "3.17.8" + resolved "https://registry.yarnpkg.com/@react-aria/table/-/table-3.17.8.tgz#bf9c72cfe13775d6ad6934855f21456d73844ef0" + integrity sha512-bXiZoxTMbsqUJsYDhHPzKc3jw0HFJ/xMsJ49a0f7mp5r9zACxNLeIU0wJ4Uvx37dnYOHKzGliG+rj5l4sph7MA== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/grid" "^3.14.5" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/live-announcer" "^3.4.4" + "@react-aria/utils" "^3.31.0" + "@react-aria/visually-hidden" "^3.8.28" + "@react-stately/collections" "^3.12.8" + "@react-stately/flags" "^3.1.2" + "@react-stately/table" "^3.15.1" + "@react-types/checkbox" "^3.10.2" + "@react-types/grid" "^3.3.6" + "@react-types/shared" "^3.32.1" + "@react-types/table" "^3.13.4" + "@swc/helpers" "^0.5.0" + +"@react-aria/tabs@^3.10.2", "@react-aria/tabs@^3.10.8": + version "3.10.8" + resolved "https://registry.yarnpkg.com/@react-aria/tabs/-/tabs-3.10.8.tgz#95c76badd8a9c9583449d0c765ab9289627847bc" + integrity sha512-sPPJyTyoAqsBh76JinBAxStOcbjZvyWFYKpJ9Uqw+XT0ObshAPPFSGeh8DiQemPs02RwJdrfARPMhyqiX8t59A== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/tabs" "^3.8.6" + "@react-types/shared" "^3.32.1" + "@react-types/tabs" "^3.3.19" + "@swc/helpers" "^0.5.0" + +"@react-aria/tag@^3.5.2", "@react-aria/tag@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-aria/tag/-/tag-3.7.2.tgz#5a655640deaf1705b8001abd636a7b96ae2250e9" + integrity sha512-JV679P5r4DftbqyNBRt7Nw9mP7dxaKPfikjyQuvUoEOa06wBLbM/hU9RJUPRvqK+Un6lgBDAmXD9NNf4N2xpdw== + dependencies: + "@react-aria/gridlist" "^3.14.1" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/list" "^3.13.1" + "@react-types/button" "^3.14.1" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/textfield@^3.17.2", "@react-aria/textfield@^3.18.2": + version "3.18.2" + resolved "https://registry.yarnpkg.com/@react-aria/textfield/-/textfield-3.18.2.tgz#d0198ac9833396f3b831e7e3c4cbe751979a4014" + integrity sha512-G+lM8VYSor6g9Yptc6hLZ6BF+0cq0pYol1z6wdQUQgJN8tg4HPtzq75lsZtlCSIznL3amgRAxJtd0dUrsAnvaQ== + dependencies: + "@react-aria/form" "^3.1.2" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/utils" "^3.31.0" + "@react-stately/form" "^3.2.2" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@react-types/textfield" "^3.12.6" + "@swc/helpers" "^0.5.0" + +"@react-aria/toast@^3.0.2", "@react-aria/toast@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@react-aria/toast/-/toast-3.0.8.tgz#50a751654a4f4917649a2a411f1e28418dc60dd1" + integrity sha512-rfJIms6AkMyQ7ZgKrMZgGfPwGcB/t1JoEwbc1PAmXcAvFI/hzF6YF7ZFDXiq38ucFsP9PnHmbXIzM9w4ccl18A== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/landmark" "^3.0.7" + "@react-aria/utils" "^3.31.0" + "@react-stately/toast" "^3.1.2" + "@react-types/button" "^3.14.1" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/toggle@^3.12.2": + version "3.12.2" + resolved "https://registry.yarnpkg.com/@react-aria/toggle/-/toggle-3.12.2.tgz#909c7c8b9bbeb2cc93a18297363eebb46354b0d4" + integrity sha512-g25XLYqJuJpt0/YoYz2Rab8ax+hBfbssllcEFh0v0jiwfk2gwTWfRU9KAZUvxIqbV8Nm8EBmrYychDpDcvW1kw== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-stately/toggle" "^3.9.2" + "@react-types/checkbox" "^3.10.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/toolbar@3.0.0-beta.15": + version "3.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.15.tgz#2b85e9a1f3e9185447e7164736cab7a859ed5f25" + integrity sha512-PNGpNIKIsCW8rxI9XXSADlLrSpikILJKKECyTRw9KwvXDRc44pezvdjGHCNinQcKsQoy5BtkK5cTSAyVqzzTXQ== + dependencies: + "@react-aria/focus" "^3.20.2" + "@react-aria/i18n" "^3.12.8" + "@react-aria/utils" "^3.28.2" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-aria/toolbar@3.0.0-beta.21": + version "3.0.0-beta.21" + resolved "https://registry.yarnpkg.com/@react-aria/toolbar/-/toolbar-3.0.0-beta.21.tgz#936929637fb89b1ba562aeeeeeaae6253a952bdd" + integrity sha512-yRCk/GD8g+BhdDgxd3I0a0c8Ni4Wyo6ERzfSoBkPkwQ4X2E2nkopmraM9D0fXw4UcIr4bnmvADzkHXtBN0XrBg== + dependencies: + "@react-aria/focus" "^3.21.2" + "@react-aria/i18n" "^3.12.13" + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/tooltip@^3.8.2", "@react-aria/tooltip@^3.8.8": + version "3.8.8" + resolved "https://registry.yarnpkg.com/@react-aria/tooltip/-/tooltip-3.8.8.tgz#a9320dd5edc953fbf7a24b9c30312408730e9743" + integrity sha512-CmHUqtXtFWmG4AHMEr9hIVex+oscK6xcM2V47gq9ijNInxe3M6UBu/dBdkgGP/jYv9N7tzCAjTR8nNIHQXwvWw== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-stately/tooltip" "^3.5.8" + "@react-types/shared" "^3.32.1" + "@react-types/tooltip" "^3.4.21" + "@swc/helpers" "^0.5.0" + +"@react-aria/tree@^3.0.2", "@react-aria/tree@^3.1.4": + version "3.1.4" + resolved "https://registry.yarnpkg.com/@react-aria/tree/-/tree-3.1.4.tgz#d264355534c4af5203a6b6f3a659681504e31f00" + integrity sha512-6pbFeN0dAsCOrFGUKU39CNjft20zCAjLfMqfkRWisL+JkUHI2nq6odUJF5jJTsU1C+1951+3oFOmVxPX+K+akQ== + dependencies: + "@react-aria/gridlist" "^3.14.1" + "@react-aria/i18n" "^3.12.13" + "@react-aria/selection" "^3.26.0" + "@react-aria/utils" "^3.31.0" + "@react-stately/tree" "^3.9.3" + "@react-types/button" "^3.14.1" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/utils@^3.28.2", "@react-aria/utils@^3.31.0": + version "3.31.0" + resolved "https://registry.yarnpkg.com/@react-aria/utils/-/utils-3.31.0.tgz#4710e35bf658234cf4b53eec9742f25e51637b12" + integrity sha512-ABOzCsZrWzf78ysswmguJbx3McQUja7yeGj6/vZo4JVsZNlxAN+E9rs381ExBRI0KzVo6iBTeX5De8eMZPJXig== + dependencies: + "@react-aria/ssr" "^3.9.10" + "@react-stately/flags" "^3.1.2" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + clsx "^2.0.0" + +"@react-aria/virtualizer@^4.1.4": + version "4.1.10" + resolved "https://registry.yarnpkg.com/@react-aria/virtualizer/-/virtualizer-4.1.10.tgz#af2e13a830d6c8e6ea31987229517285ce942d13" + integrity sha512-s0xOFh602ybTWuDrV/i6fV7Pz7vYghsY7F/RpYL/5IX9qCZ5C1FWFePpVktQAZghnd3ljH8hS8DULPeDfVLCrg== + dependencies: + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-stately/virtualizer" "^4.4.4" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-aria/visually-hidden@^3.8.22", "@react-aria/visually-hidden@^3.8.28": + version "3.8.28" + resolved "https://registry.yarnpkg.com/@react-aria/visually-hidden/-/visually-hidden-3.8.28.tgz#61fc99c2d2662e7347abe25a421d138a3a81db46" + integrity sha512-KRRjbVVob2CeBidF24dzufMxBveEUtUu7IM+hpdZKB+gxVROoh4XRLPv9SFmaH89Z7D9To3QoykVZoWD0lan6Q== + dependencies: + "@react-aria/interactions" "^3.25.6" + "@react-aria/utils" "^3.31.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-dnd/asap@^4.0.0": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@react-dnd/asap/-/asap-4.0.1.tgz#5291850a6b58ce6f2da25352a64f1b0674871aab" + integrity sha512-kLy0PJDDwvwwTXxqTFNAAllPHD73AycE9ypWeln/IguoGBEbvFcPDbCV03G52bEcC5E+YgupBE0VzHGdC8SIXg== + +"@react-dnd/invariant@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@react-dnd/invariant/-/invariant-2.0.0.tgz#09d2e81cd39e0e767d7da62df9325860f24e517e" + integrity sha512-xL4RCQBCBDJ+GRwKTFhGUW8GXa4yoDfJrPbLblc3U09ciS+9ZJXJ3Qrcs/x2IODOdIE5kQxvMmE2UKyqUictUw== + +"@react-dnd/shallowequal@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@react-dnd/shallowequal/-/shallowequal-2.0.0.tgz#a3031eb54129f2c66b2753f8404266ec7bf67f0a" + integrity sha512-Pc/AFTdwZwEKJxFJvlxrSmGe/di+aAOBn60sremrpLo6VI/6cmiUYNNwlI5KNYttg7uypzA3ILPMPgxB2GYZEg== + +"@react-stately/autocomplete@3.0.0-beta.1": + version "3.0.0-beta.1" + resolved "https://registry.yarnpkg.com/@react-stately/autocomplete/-/autocomplete-3.0.0-beta.1.tgz#2e6ab2ea9702523bf6e9a8fb95ec4b79cb1993bc" + integrity sha512-ohs6QOtJouQ+Y1+zRKiCzv57QogSTRuOA1QfrnIS1YPwKO1EDQXSqFkq2htK5+bN9GCm94yo6r4iX++SZKmLXA== + dependencies: + "@react-stately/utils" "^3.10.6" + "@swc/helpers" "^0.5.0" + +"@react-stately/calendar@3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.8.0.tgz#c8b051ef97d940eb4c1b4ac140a48b71868b628f" + integrity sha512-YAuJiR9EtVThX91gU2ay/6YgPe0LvZWEssu4BS0Atnwk5cAo32gvF5FMta9ztH1LIULdZFaypU/C1mvnayMf+Q== + dependencies: + "@internationalized/date" "^3.8.0" + "@react-stately/utils" "^3.10.6" + "@react-types/calendar" "^3.7.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/calendar@^3.8.0", "@react-stately/calendar@^3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@react-stately/calendar/-/calendar-3.9.0.tgz#22da3b99692eabf53f94a58df7768d2135664c91" + integrity sha512-U5Nf2kx9gDhJRxdDUm5gjfyUlt/uUfOvM1vDW2UA62cA6+2k2cavMLc2wNlXOb/twFtl6p0joYKHG7T4xnEFkg== + dependencies: + "@internationalized/date" "^3.10.0" + "@react-stately/utils" "^3.10.8" + "@react-types/calendar" "^3.8.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/checkbox@^3.6.13", "@react-stately/checkbox@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-stately/checkbox/-/checkbox-3.7.2.tgz#0a2293e7b97a366f94b7830d3deb2c0e9876c829" + integrity sha512-j1ycUVz5JmqhaL6mDZgDNZqBilOB8PBW096sDPFaTtuYreDx2HOd1igxiIvwlvPESZwsJP7FVM3mYnaoXtpKPA== + dependencies: + "@react-stately/form" "^3.2.2" + "@react-stately/utils" "^3.10.8" + "@react-types/checkbox" "^3.10.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/collections@^3.12.3", "@react-stately/collections@^3.12.8": + version "3.12.8" + resolved "https://registry.yarnpkg.com/@react-stately/collections/-/collections-3.12.8.tgz#f38692fb9c6384fb91d1c50052a40e595d3efa2c" + integrity sha512-AceJYLLXt1Y2XIcOPi6LEJSs4G/ubeYW3LqOCQbhfIgMaNqKfQMIfagDnPeJX9FVmPFSlgoCBxb1pTJW2vjCAQ== + dependencies: + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/color@^3.8.4", "@react-stately/color@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-stately/color/-/color-3.9.2.tgz#87ac8461a01478208c302efa47582e872ff78c65" + integrity sha512-F+6Do8W3yu/4n7MpzZtbXwVukcLTFYYDIUtpoR+Jl52UmAr9Hf1CQgkyTI2azv1ZMzj1mVrTBhpBL0q27kFZig== + dependencies: + "@internationalized/number" "^3.6.5" + "@internationalized/string" "^3.2.7" + "@react-stately/form" "^3.2.2" + "@react-stately/numberfield" "^3.10.2" + "@react-stately/slider" "^3.7.2" + "@react-stately/utils" "^3.10.8" + "@react-types/color" "^3.1.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/combobox@^3.10.4", "@react-stately/combobox@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@react-stately/combobox/-/combobox-3.12.0.tgz#71e6c9a8ee2f75edc1d233df7b6d7a0b7aeb6fbe" + integrity sha512-A6q9R/7cEa/qoQsBkdslXWvD7ztNLLQ9AhBhVN9QvzrmrH5B4ymUwcTU8lWl22ykH7RRwfonLeLXJL4C+/L2oQ== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/form" "^3.2.2" + "@react-stately/list" "^3.13.1" + "@react-stately/overlays" "^3.6.20" + "@react-stately/utils" "^3.10.8" + "@react-types/combobox" "^3.13.9" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/data@^3.12.3", "@react-stately/data@^3.14.1": + version "3.14.1" + resolved "https://registry.yarnpkg.com/@react-stately/data/-/data-3.14.1.tgz#ba5550dee9d0d8ba10a4f6c763c3251631f73582" + integrity sha512-lDNc4gZ6kVZcrABeeQZPTTnP+1ykNylSvFzAC/Hq1fs8+s54xLRvoENWIyG+yK19N9TIGEoA0AOFG8PoAun43g== + dependencies: + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/datepicker@3.14.0": + version "3.14.0" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.14.0.tgz#5f7e282d56e038ac0ef1b620fb9c1ff86253af57" + integrity sha512-JSkQfKW0+WpPQyOOeRPBLwXkVfpTUwgZJDnHBCud5kEuQiFFyeAIbL57RNXc4AX2pzY3piQa6OHnjDGTfqClxQ== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/string" "^3.2.6" + "@react-stately/form" "^3.1.3" + "@react-stately/overlays" "^3.6.15" + "@react-stately/utils" "^3.10.6" + "@react-types/datepicker" "^3.12.0" + "@react-types/shared" "^3.29.0" + "@swc/helpers" "^0.5.0" + +"@react-stately/datepicker@^3.14.0", "@react-stately/datepicker@^3.15.2": + version "3.15.2" + resolved "https://registry.yarnpkg.com/@react-stately/datepicker/-/datepicker-3.15.2.tgz#e873aecb5ec037b2da21b267c365c52443437dcb" + integrity sha512-S5GL+W37chvV8knv9v0JRv0L6hKo732qqabCCHXzOpYxkLIkV4f/y3cHdEzFWzpZ0O0Gkg7WgeYo160xOdBKYg== + dependencies: + "@internationalized/date" "^3.10.0" + "@internationalized/string" "^3.2.7" + "@react-stately/form" "^3.2.2" + "@react-stately/overlays" "^3.6.20" + "@react-stately/utils" "^3.10.8" + "@react-types/datepicker" "^3.13.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/disclosure@^3.0.3", "@react-stately/disclosure@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@react-stately/disclosure/-/disclosure-3.0.8.tgz#ff6a3cc61993d25881cb8d6a82fcf829f139e02a" + integrity sha512-/Ce/Z76y85eSBZiemfU/uEyXkBBa1RdfLRaKD13rnfUV7/nS3ae1VtNlsXgmwQjWv2pmAiSuEKYMbZfVL7q/lQ== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/dnd@^3.5.3", "@react-stately/dnd@^3.7.1": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@react-stately/dnd/-/dnd-3.7.1.tgz#23b2425553fc1cbc76821c96b30ecca1c9d16013" + integrity sha512-O1JBJ4HI1rVNKuoa5NXiC5FCrCEkr9KVBoKNlTZU8/cnQselhbEsUfMglAakO2EuwIaM1tIXoNF5J/N5P+6lTA== + dependencies: + "@react-stately/selection" "^3.20.6" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/flags@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-stately/flags/-/flags-3.1.2.tgz#5c8e5ae416d37d37e2e583d2fcb3a046293504f2" + integrity sha512-2HjFcZx1MyQXoPqcBGALwWWmgFVUk2TuKVIQxCbRq7fPyWXIl6VHcakCLurdtYC2Iks7zizvz0Idv48MQ38DWg== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-stately/form@^3.1.3", "@react-stately/form@^3.2.2": + version "3.2.2" + resolved "https://registry.yarnpkg.com/@react-stately/form/-/form-3.2.2.tgz#c1ae1264a414dd5e3e8ae0f21baf4814588d8c53" + integrity sha512-soAheOd7oaTO6eNs6LXnfn0tTqvOoe3zN9FvtIhhrErKz9XPc5sUmh3QWwR45+zKbitOi1HOjfA/gifKhZcfWw== + dependencies: + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/grid@^3.11.6": + version "3.11.6" + resolved "https://registry.yarnpkg.com/@react-stately/grid/-/grid-3.11.6.tgz#2993450ec5d0602e794f731fd49b3475f57e5547" + integrity sha512-vWPAkzpeTIsrurHfMubzMuqEw7vKzFhIJeEK5sEcLunyr1rlADwTzeWrHNbPMl66NAIAi70Dr1yNq+kahQyvMA== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/selection" "^3.20.6" + "@react-types/grid" "^3.3.6" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/layout@^4.2.2": + version "4.5.1" + resolved "https://registry.yarnpkg.com/@react-stately/layout/-/layout-4.5.1.tgz#380b506409ef09bb032baf51055ef705e4320b02" + integrity sha512-Zk92HM6a8KFdyPzslhLCOmrrsvJ28+vFBisgiKMwVhe96cWlax1m9i4ktmO43xaUpSZkn06DRD/2k0d1x+Uwjw== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/table" "^3.15.1" + "@react-stately/virtualizer" "^4.4.4" + "@react-types/grid" "^3.3.6" + "@react-types/shared" "^3.32.1" + "@react-types/table" "^3.13.4" + "@swc/helpers" "^0.5.0" + +"@react-stately/list@^3.12.1", "@react-stately/list@^3.13.1": + version "3.13.1" + resolved "https://registry.yarnpkg.com/@react-stately/list/-/list-3.13.1.tgz#4afd36a87c8fd991a4447d28cc76d51fffddb837" + integrity sha512-eHaoauh21twbcl0kkwULhVJ+CzYcy1jUjMikNVMHOQdhr4WIBdExf7PmSgKHKqsSPhpGg6IpTCY2dUX3RycjDg== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/selection" "^3.20.6" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/menu@^3.9.3", "@react-stately/menu@^3.9.8": + version "3.9.8" + resolved "https://registry.yarnpkg.com/@react-stately/menu/-/menu-3.9.8.tgz#5c2e781dadc3331bc5b3735fe30bf62616f9145f" + integrity sha512-bo0NOhofnTHLESiYfsSSw6gyXiPVJJ0UlN2igUXtJk5PmyhWjFzUzTzcnd7B028OB0si9w3LIWM3stqz5271Eg== + dependencies: + "@react-stately/overlays" "^3.6.20" + "@react-types/menu" "^3.10.5" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/numberfield@^3.10.2", "@react-stately/numberfield@^3.9.11": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@react-stately/numberfield/-/numberfield-3.10.2.tgz#aa1fcaec84cd441ea5e847dd3e9eca784045be21" + integrity sha512-jlKVFYaH3RX5KvQ7a+SAMQuPccZCzxLkeYkBE64u1Zvi7YhJ8hkTMHG/fmZMbk1rHlseE2wfBdk0Rlya3MvoNQ== + dependencies: + "@internationalized/number" "^3.6.5" + "@react-stately/form" "^3.2.2" + "@react-stately/utils" "^3.10.8" + "@react-types/numberfield" "^3.8.15" + "@swc/helpers" "^0.5.0" + +"@react-stately/overlays@^3.6.15", "@react-stately/overlays@^3.6.20": + version "3.6.20" + resolved "https://registry.yarnpkg.com/@react-stately/overlays/-/overlays-3.6.20.tgz#e638ad0e073b6cf1d27f018aa41a4ce0fbae5f5b" + integrity sha512-YAIe+uI8GUXX8F/0Pzr53YeC5c/bjqbzDFlV8NKfdlCPa6+Jp4B/IlYVjIooBj9+94QvbQdjylegvYWK/iPwlg== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/overlays" "^3.9.2" + "@swc/helpers" "^0.5.0" + +"@react-stately/radio@^3.10.12", "@react-stately/radio@^3.11.2": + version "3.11.2" + resolved "https://registry.yarnpkg.com/@react-stately/radio/-/radio-3.11.2.tgz#a149fb9448dc258441662893f83a70e88e4d4aea" + integrity sha512-UM7L6AW+k8edhSBUEPZAqiWNRNadfOKK7BrCXyBiG79zTz0zPcXRR+N+gzkDn7EMSawDeyK1SHYUuoSltTactg== + dependencies: + "@react-stately/form" "^3.2.2" + "@react-stately/utils" "^3.10.8" + "@react-types/radio" "^3.9.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/searchfield@^3.5.11", "@react-stately/searchfield@^3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@react-stately/searchfield/-/searchfield-3.5.16.tgz#3b768870d08fa2ef7747513d02d167717961d548" + integrity sha512-MRfqT1lZ24r94GuFNcGJXsfijZoWjSMySCT60T6NXtbOzVPuAF3K+pL70Rayq/EWLJjS2NPHND11VTs0VdcE0Q== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/searchfield" "^3.6.6" + "@swc/helpers" "^0.5.0" + +"@react-stately/select@^3.6.12", "@react-stately/select@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-stately/select/-/select-3.8.0.tgz#ccb1b7d6d0f40b166444f3df27273892854ff23e" + integrity sha512-A721nlt0DSCDit0wKvhcrXFTG5Vv1qkEVkeKvobmETZy6piKvwh0aaN8iQno5AFuZaj1iOZeNjZ/20TsDJR/4A== + dependencies: + "@react-stately/form" "^3.2.2" + "@react-stately/list" "^3.13.1" + "@react-stately/overlays" "^3.6.20" + "@react-stately/utils" "^3.10.8" + "@react-types/select" "^3.11.0" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/selection@^3.20.1", "@react-stately/selection@^3.20.6": + version "3.20.6" + resolved "https://registry.yarnpkg.com/@react-stately/selection/-/selection-3.20.6.tgz#17d4d4553403de6ab690172a8d36e0423a5173fb" + integrity sha512-a0bjuP2pJYPKEiedz2Us1W1aSz0iHRuyeQEdBOyL6Z6VUa6hIMq9H60kvseir2T85cOa4QggizuRV7mcO6bU5w== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/slider@^3.6.3", "@react-stately/slider@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@react-stately/slider/-/slider-3.7.2.tgz#9dfe6f7e74397f717b1623bc06ba8e375510d056" + integrity sha512-EVBHUdUYwj++XqAEiQg2fGi8Reccznba0uyQ3gPejF0pAc390Q/J5aqiTEDfiCM7uJ6WHxTM6lcCqHQBISk2dQ== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@react-types/slider" "^3.8.2" + "@swc/helpers" "^0.5.0" + +"@react-stately/table@^3.14.1", "@react-stately/table@^3.15.1": + version "3.15.1" + resolved "https://registry.yarnpkg.com/@react-stately/table/-/table-3.15.1.tgz#3a2f5ca0788cea200c4c96858604fb4c0139f8b0" + integrity sha512-MhMAgE/LgAzHcAn1P3p/nQErzJ6DiixSJ1AOt2JlnAKEb5YJg4ATKWCb2IjBLwywt9ZCzfm3KMUzkctZqAoxwA== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/flags" "^3.1.2" + "@react-stately/grid" "^3.11.6" + "@react-stately/selection" "^3.20.6" + "@react-stately/utils" "^3.10.8" + "@react-types/grid" "^3.3.6" + "@react-types/shared" "^3.32.1" + "@react-types/table" "^3.13.4" + "@swc/helpers" "^0.5.0" + +"@react-stately/tabs@^3.8.1", "@react-stately/tabs@^3.8.6": + version "3.8.6" + resolved "https://registry.yarnpkg.com/@react-stately/tabs/-/tabs-3.8.6.tgz#c71e3ed2462d89ad9c06fb78c69b2069625c68fd" + integrity sha512-9RYxmgjVIxUpIsGKPIF7uRoHWOEz8muwaYiStCVeyiYBPmarvZoIYtTXcwSMN/vEs7heVN5uGCL6/bfdY4+WiA== + dependencies: + "@react-stately/list" "^3.13.1" + "@react-types/shared" "^3.32.1" + "@react-types/tabs" "^3.3.19" + "@swc/helpers" "^0.5.0" + +"@react-stately/toast@^3.1.0", "@react-stately/toast@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-stately/toast/-/toast-3.1.2.tgz#0502040b6bd57479eaba1bca2f4c66e9e957e55a" + integrity sha512-HiInm7bck32khFBHZThTQaAF6e6/qm57F4mYRWdTq8IVeGDzpkbUYibnLxRhk0UZ5ybc6me+nqqPkG/lVmM42Q== + dependencies: + "@swc/helpers" "^0.5.0" + use-sync-external-store "^1.4.0" + +"@react-stately/toggle@^3.8.3", "@react-stately/toggle@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-stately/toggle/-/toggle-3.9.2.tgz#8a50def68efdcefa268a870deda8bb65e5f054a8" + integrity sha512-dOxs9wrVXHUmA7lc8l+N9NbTJMAaXcYsnNGsMwfXIXQ3rdq+IjWGNYJ52UmNQyRYFcg0jrzRrU16TyGbNjOdNQ== + dependencies: + "@react-stately/utils" "^3.10.8" + "@react-types/checkbox" "^3.10.2" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/tooltip@^3.5.3", "@react-stately/tooltip@^3.5.8": + version "3.5.8" + resolved "https://registry.yarnpkg.com/@react-stately/tooltip/-/tooltip-3.5.8.tgz#c4a329c63294e8ccae3d9ee7853d40c2fb93ce73" + integrity sha512-gkcUx2ROhCiGNAYd2BaTejakXUUNLPnnoJ5+V/mN480pN+OrO8/2V9pqb/IQmpqxLsso93zkM3A4wFHHLBBmPQ== + dependencies: + "@react-stately/overlays" "^3.6.20" + "@react-types/tooltip" "^3.4.21" + "@swc/helpers" "^0.5.0" + +"@react-stately/tree@^3.8.9", "@react-stately/tree@^3.9.3": + version "3.9.3" + resolved "https://registry.yarnpkg.com/@react-stately/tree/-/tree-3.9.3.tgz#398de3406d2a06477bb0af2bdb2a0021265eeade" + integrity sha512-ZngG79nLFxE/GYmpwX6E/Rma2MMkzdoJPRI3iWk3dgqnGMMzpPnUp/cvjDsU3UHF7xDVusC5BT6pjWN0uxCIFQ== + dependencies: + "@react-stately/collections" "^3.12.8" + "@react-stately/selection" "^3.20.6" + "@react-stately/utils" "^3.10.8" + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-stately/utils@^3.10.6", "@react-stately/utils@^3.10.8": + version "3.10.8" + resolved "https://registry.yarnpkg.com/@react-stately/utils/-/utils-3.10.8.tgz#fdb9d172f7bbc2d083e69190f5ef0edfa4b4392f" + integrity sha512-SN3/h7SzRsusVQjQ4v10LaVsDc81jyyR0DD5HnsQitm/I5WDpaSr2nRHtyloPFU48jlql1XX/S04T2DLQM7Y3g== + dependencies: + "@swc/helpers" "^0.5.0" + +"@react-stately/virtualizer@^4.3.2", "@react-stately/virtualizer@^4.4.4": + version "4.4.4" + resolved "https://registry.yarnpkg.com/@react-stately/virtualizer/-/virtualizer-4.4.4.tgz#b2a48bf6bf22f59532d9c6d71d010845b0088ed1" + integrity sha512-ri8giqXSZOrznZDCCOE4U36wSkOhy+hrFK7yo/YVcpxTqqp3d3eisfKMqbDsgqBW+XTHycTU/xeAf0u9NqrfpQ== + dependencies: + "@react-types/shared" "^3.32.1" + "@swc/helpers" "^0.5.0" + +"@react-types/autocomplete@3.0.0-alpha.30": + version "3.0.0-alpha.30" + resolved "https://registry.yarnpkg.com/@react-types/autocomplete/-/autocomplete-3.0.0-alpha.30.tgz#c4672644f762d112557c54e78fddf1f8f9ae4146" + integrity sha512-9neGygI+stJqiEFHzoc1jMySj6lOc4MUmBmu0uGn2zdOG2zxaAZSjh1pd9AJkHNyZ4j/n5rVXMo+v3RNkUntNw== + dependencies: + "@react-types/combobox" "^3.13.4" + "@react-types/searchfield" "^3.6.1" + "@react-types/shared" "^3.29.0" + +"@react-types/breadcrumbs@^3.7.17": + version "3.7.17" + resolved "https://registry.yarnpkg.com/@react-types/breadcrumbs/-/breadcrumbs-3.7.17.tgz#e584352cc4f79e638e20774af04f28064cd9b66b" + integrity sha512-IhvVTcfli5o/UDlGACXxjlor2afGlMQA8pNR3faH0bBUay1Fmm3IWktVw9Xwmk+KraV2RTAg9e+E6p8DOQZfiw== + dependencies: + "@react-types/link" "^3.6.5" + "@react-types/shared" "^3.32.1" + +"@react-types/button@^3.12.0", "@react-types/button@^3.14.1": + version "3.14.1" + resolved "https://registry.yarnpkg.com/@react-types/button/-/button-3.14.1.tgz#41c25f7c7dd1b31a359a6af9cbec5bed5dbb5aa1" + integrity sha512-D8C4IEwKB7zEtiWYVJ3WE/5HDcWlze9mLWQ5hfsBfpePyWCgO3bT/+wjb/7pJvcAocrkXo90QrMm85LcpBtrpg== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/calendar@^3.7.0", "@react-types/calendar@^3.8.0": + version "3.8.0" + resolved "https://registry.yarnpkg.com/@react-types/calendar/-/calendar-3.8.0.tgz#51dad3445586f1c22886c35499cfcc872462a30f" + integrity sha512-ZDZgfZgbz1ydWOFs1mH7QFfX3ioJrmb3Y/lkoubQE0HWXLZzyYNvhhKyFJRS1QJ40IofLSBHriwbQb/tsUnGlw== + dependencies: + "@internationalized/date" "^3.10.0" + "@react-types/shared" "^3.32.1" + +"@react-types/checkbox@^3.10.2": + version "3.10.2" + resolved "https://registry.yarnpkg.com/@react-types/checkbox/-/checkbox-3.10.2.tgz#0190c9690e3649348a4d7045b168cbda657ce9de" + integrity sha512-ktPkl6ZfIdGS1tIaGSU/2S5Agf2NvXI9qAgtdMDNva0oLyAZ4RLQb6WecPvofw1J7YKXu0VA5Mu7nlX+FM2weQ== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/color@^3.1.2": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@react-types/color/-/color-3.1.2.tgz#06a0e81b463f3a8d4553e7cd535b2881d721e231" + integrity sha512-NP0TAY3j4tlMztOp/bBfMlPwC9AQKTjSiTFmc2oQNkx5M4sl3QpPqFPosdt7jZ8M4nItvfCWZrlZGjST4SB83A== + dependencies: + "@react-types/shared" "^3.32.1" + "@react-types/slider" "^3.8.2" + +"@react-types/combobox@^3.13.4", "@react-types/combobox@^3.13.9": + version "3.13.9" + resolved "https://registry.yarnpkg.com/@react-types/combobox/-/combobox-3.13.9.tgz#58bc5c39ca1d7bdbb4beebf79d2ba11b337e927f" + integrity sha512-G6GmLbzVkLW6VScxPAr/RtliEyPhBClfYaIllK1IZv+Z42SVnOpKzhnoe79BpmiFqy1AaC3+LjZX783mrsHCwA== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/datepicker@^3.12.0", "@react-types/datepicker@^3.13.2": + version "3.13.2" + resolved "https://registry.yarnpkg.com/@react-types/datepicker/-/datepicker-3.13.2.tgz#775e43b6edcb8d3d5968e0a35cfacd14be3c847c" + integrity sha512-+M6UZxJnejYY8kz0spbY/hP08QJ5rsZ3aNarRQQHc48xV2oelFLX5MhAqizfLEsvyfb0JYrhWoh4z1xZtAmYCg== + dependencies: + "@internationalized/date" "^3.10.0" + "@react-types/calendar" "^3.8.0" + "@react-types/overlays" "^3.9.2" + "@react-types/shared" "^3.32.1" + +"@react-types/dialog@^3.5.17", "@react-types/dialog@^3.5.22": + version "3.5.22" + resolved "https://registry.yarnpkg.com/@react-types/dialog/-/dialog-3.5.22.tgz#ed772c303042c6ee5e8a9bc9e58b5b9d08ed634b" + integrity sha512-smSvzOcqKE196rWk0oqJDnz+ox5JM5+OT0PmmJXiUD4q7P5g32O6W5Bg7hMIFUI9clBtngo8kLaX2iMg+GqAzg== + dependencies: + "@react-types/overlays" "^3.9.2" + "@react-types/shared" "^3.32.1" + +"@react-types/form@^3.7.11": + version "3.7.16" + resolved "https://registry.yarnpkg.com/@react-types/form/-/form-3.7.16.tgz#4285880a03db2b9f664246b6f2f2421ef18a49da" + integrity sha512-Sb7KJoWEaQ/e4XIY+xRbjKvbP1luome98ZXevpD+zVSyGjEcfIroebizP6K1yMHCWP/043xH6GUkgEqWPoVGjg== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/grid@^3.3.1", "@react-types/grid@^3.3.6": + version "3.3.6" + resolved "https://registry.yarnpkg.com/@react-types/grid/-/grid-3.3.6.tgz#9fc60f5baa8a1668bb2257a981dd514dd64706c3" + integrity sha512-vIZJlYTii2n1We9nAugXwM2wpcpsC6JigJFBd6vGhStRdRWRoU4yv1Gc98Usbx0FQ/J7GLVIgeG8+1VMTKBdxw== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/link@^3.6.5": + version "3.6.5" + resolved "https://registry.yarnpkg.com/@react-types/link/-/link-3.6.5.tgz#28cf2b90f69e83af7ff507021eec0449f148eb45" + integrity sha512-+I2s3XWBEvLrzts0GnNeA84mUkwo+a7kLUWoaJkW0TOBDG7my95HFYxF9WnqKye7NgpOkCqz4s3oW96xPdIniQ== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/listbox@^3.7.4": + version "3.7.4" + resolved "https://registry.yarnpkg.com/@react-types/listbox/-/listbox-3.7.4.tgz#712329de62c0fddf44c062bb18c51135309c9fe8" + integrity sha512-p4YEpTl/VQGrqVE8GIfqTS5LkT5jtjDTbVeZgrkPnX/fiPhsfbTPiZ6g0FNap4+aOGJFGEEZUv2q4vx+rCORww== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/menu@^3.10.5": + version "3.10.5" + resolved "https://registry.yarnpkg.com/@react-types/menu/-/menu-3.10.5.tgz#0e3a66aab3c636dc3ef965529640bb678b13a431" + integrity sha512-HBTrKll2hm0VKJNM4ubIv1L9MNo8JuOnm2G3M+wXvb6EYIyDNxxJkhjsqsGpUXJdAOSkacHBDcNh2HsZABNX4A== + dependencies: + "@react-types/overlays" "^3.9.2" + "@react-types/shared" "^3.32.1" + +"@react-types/meter@^3.4.13": + version "3.4.13" + resolved "https://registry.yarnpkg.com/@react-types/meter/-/meter-3.4.13.tgz#ddd54e1d56a9af79646d832a3cf4a8979e473ead" + integrity sha512-EiarfbpHcvmeyXvXcr6XLaHkNHuGc4g7fBVEiDPwssFJKKfbUzqnnknDxPjyspqUVRcXC08CokS98J1jYobqDg== + dependencies: + "@react-types/progress" "^3.5.16" + +"@react-types/numberfield@^3.8.15": + version "3.8.15" + resolved "https://registry.yarnpkg.com/@react-types/numberfield/-/numberfield-3.8.15.tgz#0fcd77217bae5d7a2bf35d41c7eb61d8ae52bc03" + integrity sha512-97r92D23GKCOjGIGMeW9nt+/KlfM3GeWH39Czcmd2/D5y3k6z4j0avbsfx2OttCtJszrnENjw3GraYGYI2KosQ== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/overlays@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-types/overlays/-/overlays-3.9.2.tgz#721dc248afcb42db988391037a6386bb61556cd4" + integrity sha512-Q0cRPcBGzNGmC8dBuHyoPR7N3057KTS5g+vZfQ53k8WwmilXBtemFJPLsogJbspuewQ/QJ3o2HYsp2pne7/iNw== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/progress@^3.5.16": + version "3.5.16" + resolved "https://registry.yarnpkg.com/@react-types/progress/-/progress-3.5.16.tgz#f40e1b674e630276d6412297a92eb0dd3761d426" + integrity sha512-I9tSdCFfvQ7gHJtm90VAKgwdTWXQgVNvLRStEc0z9h+bXBxdvZb+QuiRPERChwFQ9VkK4p4rDqaFo69nDqWkpw== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/radio@^3.9.2": + version "3.9.2" + resolved "https://registry.yarnpkg.com/@react-types/radio/-/radio-3.9.2.tgz#c6ac396b49cc03334e4bb63a96f366effce3a615" + integrity sha512-3UcJXu37JrTkRyP4GJPDBU7NmDTInrEdOe+bVzA1j4EegzdkJmLBkLg5cLDAbpiEHB+xIsvbJdx6dxeMuc+H3g== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/searchfield@^3.6.1", "@react-types/searchfield@^3.6.6": + version "3.6.6" + resolved "https://registry.yarnpkg.com/@react-types/searchfield/-/searchfield-3.6.6.tgz#fd41bd78246789ac4284462abe222b6f85d191b2" + integrity sha512-cl3itr/fk7wbIQc2Gz5Ie8aVeUmPjVX/mRGS5/EXlmzycAKNYTvqf2mlxwObLndtLISmt7IgNjRRhbUUDI8Ang== + dependencies: + "@react-types/shared" "^3.32.1" + "@react-types/textfield" "^3.12.6" + +"@react-types/select@^3.11.0": + version "3.11.0" + resolved "https://registry.yarnpkg.com/@react-types/select/-/select-3.11.0.tgz#808aec480f0cc20075953af9717ca38d1eb15b8d" + integrity sha512-SzIsMFVPCbXE1Z1TLfpdfiwJ1xnIkcL1/CjGilmUKkNk5uT7rYX1xCJqWCjXI0vAU1xM4Qn+T3n8de4fw6HRBg== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/shared@^3.29.0", "@react-types/shared@^3.32.1": + version "3.32.1" + resolved "https://registry.yarnpkg.com/@react-types/shared/-/shared-3.32.1.tgz#abfeb839d65d0abe923576f34ac08342c25dfa55" + integrity sha512-famxyD5emrGGpFuUlgOP6fVW2h/ZaF405G5KDi3zPHzyjAWys/8W6NAVJtNbkCkhedmvL0xOhvt8feGXyXaw5w== + +"@react-types/slider@^3.8.2": + version "3.8.2" + resolved "https://registry.yarnpkg.com/@react-types/slider/-/slider-3.8.2.tgz#37e02c42514aca842954c715082d1ae06a661ee4" + integrity sha512-MQYZP76OEOYe7/yA2To+Dl0LNb0cKKnvh5JtvNvDnAvEprn1RuLiay8Oi/rTtXmc2KmBa4VdTcsXsmkbbkeN2Q== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/switch@^3.5.15": + version "3.5.15" + resolved "https://registry.yarnpkg.com/@react-types/switch/-/switch-3.5.15.tgz#43806d6e7034d1d07e20c89ec9618e607fef9e62" + integrity sha512-r/ouGWQmIeHyYSP1e5luET+oiR7N7cLrAlWsrAfYRWHxqXOSNQloQnZJ3PLHrKFT02fsrQhx2rHaK2LfKeyN3A== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/table@^3.12.0", "@react-types/table@^3.13.4": + version "3.13.4" + resolved "https://registry.yarnpkg.com/@react-types/table/-/table-3.13.4.tgz#c3d5952d4bd2a04992255850538856829b12c99a" + integrity sha512-I/DYiZQl6aNbMmjk90J9SOhkzVDZvyA3Vn3wMWCiajkMNjvubFhTfda5DDf2SgFP5l0Yh6TGGH5XumRv9LqL5Q== + dependencies: + "@react-types/grid" "^3.3.6" + "@react-types/shared" "^3.32.1" + +"@react-types/tabs@^3.3.19": + version "3.3.19" + resolved "https://registry.yarnpkg.com/@react-types/tabs/-/tabs-3.3.19.tgz#344a22bd15400b738aebc26918cf96dacde1ffef" + integrity sha512-fE+qI43yR5pAMpeqPxGqQq9jDHXEPqXskuxNHERMW0PYMdPyem2Cw6goc5F4qeZO3Hf6uPZgHkvJz2OAq7TbBw== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/textfield@^3.12.6": + version "3.12.6" + resolved "https://registry.yarnpkg.com/@react-types/textfield/-/textfield-3.12.6.tgz#0f90a4108c8d75e7c2c26753e760cd580339be12" + integrity sha512-hpEVKE+M3uUkTjw2WrX1NrH/B3rqDJFUa+ViNK2eVranLY4ZwFqbqaYXSzHupOF3ecSjJJv2C103JrwFvx6TPQ== + dependencies: + "@react-types/shared" "^3.32.1" + +"@react-types/tooltip@^3.4.21": + version "3.4.21" + resolved "https://registry.yarnpkg.com/@react-types/tooltip/-/tooltip-3.4.21.tgz#63596cf87d7166499656bc15f212c75c9ffa8991" + integrity sha512-ugGHOZU6WbOdeTdbjnaEc+Ms7/WhsUCg+T3PCOIeOT9FG02Ce189yJ/+hd7oqL/tVwIhEMYJIqSCgSELFox+QA== + dependencies: + "@react-types/overlays" "^3.9.2" + "@react-types/shared" "^3.32.1" + +"@rolldown/pluginutils@1.0.0-beta.47": + version "1.0.0-beta.47" + resolved "https://registry.yarnpkg.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.47.tgz#c282c4a8c39f3d6d2f1086aae09a34e6241f7a50" + integrity sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw== + +"@rollup/pluginutils@^5.1.4": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-5.3.0.tgz#57ba1b0cbda8e7a3c597a4853c807b156e21a7b4" + integrity sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^2.0.2" + picomatch "^4.0.2" + +"@rollup/rollup-android-arm-eabi@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz#7e478b66180c5330429dd161bf84dad66b59c8eb" + integrity sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w== + +"@rollup/rollup-android-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz#2b025510c53a5e3962d3edade91fba9368c9d71c" + integrity sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w== + +"@rollup/rollup-darwin-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz#3577c38af68ccf34c03e84f476bfd526abca10a0" + integrity sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA== + +"@rollup/rollup-darwin-x64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz#2bf5f2520a1f3b551723d274b9669ba5b75ed69c" + integrity sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ== + +"@rollup/rollup-freebsd-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz#4bb9cc80252564c158efc0710153c71633f1927c" + integrity sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w== + +"@rollup/rollup-freebsd-x64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz#2301289094d49415a380cf942219ae9d8b127440" + integrity sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q== + +"@rollup/rollup-linux-arm-gnueabihf@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz#1d03d776f2065e09fc141df7d143476e94acca88" + integrity sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw== + +"@rollup/rollup-linux-arm-musleabihf@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz#8623de0e040b2fd52a541c602688228f51f96701" + integrity sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg== + +"@rollup/rollup-linux-arm64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz#ce2d1999bc166277935dde0301cde3dd0417fb6e" + integrity sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w== + +"@rollup/rollup-linux-arm64-musl@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz#88c2523778444da952651a2219026416564a4899" + integrity sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A== + +"@rollup/rollup-linux-loong64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz#578ca2220a200ac4226c536c10c8cc6e4f276714" + integrity sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g== + +"@rollup/rollup-linux-ppc64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz#aa338d3effd4168a20a5023834a74ba2c3081293" + integrity sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw== + +"@rollup/rollup-linux-riscv64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz#16ba582f9f6cff58119aa242782209b1557a1508" + integrity sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g== + +"@rollup/rollup-linux-riscv64-musl@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz#e404a77ebd6378483888b8064c703adb011340ab" + integrity sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A== + +"@rollup/rollup-linux-s390x-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz#92ad52d306227c56bec43d96ad2164495437ffe6" + integrity sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg== + +"@rollup/rollup-linux-x64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz#fd0dea3bb9aa07e7083579f25e1c2285a46cb9fa" + integrity sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w== + +"@rollup/rollup-linux-x64-musl@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz#37a3efb09f18d555f8afc490e1f0444885de8951" + integrity sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q== + +"@rollup/rollup-openharmony-arm64@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz#c489bec9f4f8320d42c9b324cca220c90091c1f7" + integrity sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw== + +"@rollup/rollup-win32-arm64-msvc@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz#152832b5f79dc22d1606fac3db946283601b7080" + integrity sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw== + +"@rollup/rollup-win32-ia32-msvc@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz#54d91b2bb3bf3e9f30d32b72065a4e52b3a172a5" + integrity sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA== + +"@rollup/rollup-win32-x64-gnu@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz#df9df03e61a003873efec8decd2034e7f135c71e" + integrity sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg== + +"@rollup/rollup-win32-x64-msvc@4.53.3": + version "4.53.3" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz#38ae84f4c04226c1d56a3b17296ef1e0460ecdfe" + integrity sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + +"@rushstack/eslint-patch@^1.10.3": + version "1.15.0" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.15.0.tgz#8184bcb37791e6d3c3c13a9bfbe4af263f66665f" + integrity sha512-ojSshQPKwVvSMR8yT2L/QtUkV5SXi/IfDiJ4/8d6UbTPjiHVmxZzUAzGD8Tzks1b9+qQkZa0isUOvYObedITaw== + +"@rushstack/node-core-library@5.18.0": + version "5.18.0" + resolved "https://registry.yarnpkg.com/@rushstack/node-core-library/-/node-core-library-5.18.0.tgz#b184c9f375fba45bca69cba60e7938d495d11c53" + integrity sha512-XDebtBdw5S3SuZIt+Ra2NieT8kQ3D2Ow1HxhDQ/2soinswnOu9e7S69VSwTOLlQnx5mpWbONu+5JJjDxMAb6Fw== + dependencies: + ajv "~8.13.0" + ajv-draft-04 "~1.0.0" + ajv-formats "~3.0.1" + fs-extra "~11.3.0" + import-lazy "~4.0.0" + jju "~1.4.0" + resolve "~1.22.1" + semver "~7.5.4" + +"@rushstack/problem-matcher@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@rushstack/problem-matcher/-/problem-matcher-0.1.1.tgz#db9303ef3c47010c8aba5841e8c9511e091159df" + integrity sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA== + +"@rushstack/rig-package@0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@rushstack/rig-package/-/rig-package-0.6.0.tgz#c80f93fe2c0d9d4977fc925ed9ce9decb75047a5" + integrity sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw== + dependencies: + resolve "~1.22.1" + strip-json-comments "~3.1.1" + +"@rushstack/terminal@0.19.3": + version "0.19.3" + resolved "https://registry.yarnpkg.com/@rushstack/terminal/-/terminal-0.19.3.tgz#d09ba5a0c2cb5358eba443ea3819936b654c16d9" + integrity sha512-0P8G18gK9STyO+CNBvkKPnWGMxESxecTYqOcikHOVIHXa9uAuTK+Fw8TJq2Gng1w7W6wTC9uPX6hGNvrMll2wA== + dependencies: + "@rushstack/node-core-library" "5.18.0" + "@rushstack/problem-matcher" "0.1.1" + supports-color "~8.1.1" + +"@rushstack/ts-command-line@5.1.3": + version "5.1.3" + resolved "https://registry.yarnpkg.com/@rushstack/ts-command-line/-/ts-command-line-5.1.3.tgz#c3e4e3d14b208f3d60166be4e7c9f9c9cfa0a85e" + integrity sha512-Kdv0k/BnnxIYFlMVC1IxrIS0oGQd4T4b7vKfx52Y2+wk2WZSDFIvedr7JrhenzSlm3ou5KwtoTGTGd5nbODRug== + dependencies: + "@rushstack/terminal" "0.19.3" + "@types/argparse" "1.0.38" + argparse "~1.0.9" + string-argv "~0.3.1" + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@swc/core-darwin-arm64@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.15.2.tgz#591fde48757f9c66f050eb82353def199c9967af" + integrity sha512-Ghyz4RJv4zyXzrUC1B2MLQBbppIB5c4jMZJybX2ebdEQAvryEKp3gq1kBksCNsatKGmEgXul88SETU19sMWcrw== + +"@swc/core-darwin-x64@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.15.2.tgz#f0c229fd21b0ef658cf50adb8b9a5f8c1919d2ec" + integrity sha512-7n/PGJOcL2QoptzL42L5xFFfXY5rFxLHnuz1foU+4ruUTG8x2IebGhtwVTpaDN8ShEv2UZObBlT1rrXTba15Zw== + +"@swc/core-linux-arm-gnueabihf@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.15.2.tgz#ab6d8535ab0294fb743044665c1c17330ccc2181" + integrity sha512-ZUQVCfRJ9wimuxkStRSlLwqX4TEDmv6/J+E6FicGkQ6ssLMWoKDy0cAo93HiWt/TWEee5vFhFaSQYzCuBEGO6A== + +"@swc/core-linux-arm64-gnu@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.15.2.tgz#c5db7bbba6af3bd93fd79b74850cf2fe04f1c074" + integrity sha512-GZh3pYBmfnpQ+JIg+TqLuz+pM+Mjsk5VOzi8nwKn/m+GvQBsxD5ectRtxuWUxMGNG8h0lMy4SnHRqdK3/iJl7A== + +"@swc/core-linux-arm64-musl@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.15.2.tgz#31cd61e6c83595248fda70a70e596f0a7f6cdf97" + integrity sha512-5av6VYZZeneiYIodwzGMlnyVakpuYZryGzFIbgu1XP8wVylZxduEzup4eP8atiMDFmIm+s4wn8GySJmYqeJC0A== + +"@swc/core-linux-x64-gnu@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.15.2.tgz#c857e95635fa2beaf6d3ecb9b1bd97ade5cda43a" + integrity sha512-1nO/UfdCLuT/uE/7oB3EZgTeZDCIa6nL72cFEpdegnqpJVNDI6Qb8U4g/4lfVPkmHq2lvxQ0L+n+JdgaZLhrRA== + +"@swc/core-linux-x64-musl@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.15.2.tgz#afa817865271f24502a0805cfab70ba553ade146" + integrity sha512-Ksfrb0Tx310kr+TLiUOvB/I80lyZ3lSOp6cM18zmNRT/92NB4mW8oX2Jo7K4eVEI2JWyaQUAFubDSha2Q+439A== + +"@swc/core-win32-arm64-msvc@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.15.2.tgz#5696added38837b6b3f442d63989ef4fcaa2d3de" + integrity sha512-IzUb5RlMUY0r1A9IuJrQ7Tbts1wWb73/zXVXT8VhewbHGoNlBKE0qUhKMED6Tv4wDF+pmbtUJmKXDthytAvLmg== + +"@swc/core-win32-ia32-msvc@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.15.2.tgz#3e42427998d49b54c55d49752b410309c7d02357" + integrity sha512-kCATEzuY2LP9AlbU2uScjcVhgnCAkRdu62vbce17Ro5kxEHxYWcugkveyBRS3AqZGtwAKYbMAuNloer9LS/hpw== + +"@swc/core-win32-x64-msvc@1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.15.2.tgz#fa6505e20a3753b6884b35353d1614a03c54df7f" + integrity sha512-iJaHeYCF4jTn7OEKSa3KRiuVFIVYts8jYjNmCdyz1u5g8HRyTDISD76r8+ljEOgm36oviRQvcXaw6LFp1m0yyA== + +"@swc/core@^1.13.5": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.15.2.tgz#94c783f959fdc12c9d811b8345d791e9592a628a" + integrity sha512-OQm+yJdXxvSjqGeaWhP6Ia264ogifwAO7Q12uTDVYj/Ks4jBTI4JknlcjDRAXtRhqbWsfbZyK/5RtuIPyptk3w== + dependencies: + "@swc/counter" "^0.1.3" + "@swc/types" "^0.1.25" + optionalDependencies: + "@swc/core-darwin-arm64" "1.15.2" + "@swc/core-darwin-x64" "1.15.2" + "@swc/core-linux-arm-gnueabihf" "1.15.2" + "@swc/core-linux-arm64-gnu" "1.15.2" + "@swc/core-linux-arm64-musl" "1.15.2" + "@swc/core-linux-x64-gnu" "1.15.2" + "@swc/core-linux-x64-musl" "1.15.2" + "@swc/core-win32-arm64-msvc" "1.15.2" + "@swc/core-win32-ia32-msvc" "1.15.2" + "@swc/core-win32-x64-msvc" "1.15.2" + +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/helpers@0.5.15": + version "0.5.15" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.15.tgz#79efab344c5819ecf83a43f3f9f811fc84b516d7" + integrity sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g== + dependencies: + tslib "^2.8.0" + +"@swc/helpers@^0.5.0": + version "0.5.17" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.17.tgz#5a7be95ac0f0bf186e7e6e890e7a6f6cda6ce971" + integrity sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A== + dependencies: + tslib "^2.8.0" + +"@swc/types@^0.1.25": + version "0.1.25" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.25.tgz#b517b2a60feb37dd933e542d93093719e4cf1078" + integrity sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g== + dependencies: + "@swc/counter" "^0.1.3" + +"@tanstack/eslint-plugin-query@5.66.1": + version "5.66.1" + resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.66.1.tgz#9951e4d3633ca6248196742cad437b4d7c760cd7" + integrity sha512-pYMVTGgJ7yPk9Rm6UWEmbY6TX0EmMmxJqYkthgeDCwEznToy2m+W928nUODFirtZBZlhBsqHy33LO0kyTlgf0w== + dependencies: + "@typescript-eslint/utils" "^8.18.1" + +"@tanstack/eslint-plugin-query@5.91.2": + version "5.91.2" + resolved "https://registry.yarnpkg.com/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.91.2.tgz#dc47394f9d08d78ce811c405b9620a259e4368cb" + integrity sha512-UPeWKl/Acu1IuuHJlsN+eITUHqAaa9/04geHHPedY8siVarSaWprY0SVMKrkpKfk5ehRT7+/MZ5QwWuEtkWrFw== + dependencies: + "@typescript-eslint/utils" "^8.44.1" + +"@tanstack/query-core@5.90.10": + version "5.90.10" + resolved "https://registry.yarnpkg.com/@tanstack/query-core/-/query-core-5.90.10.tgz#2704b038277fb41e631f356e7428951b5354ed13" + integrity sha512-EhZVFu9rl7GfRNuJLJ3Y7wtbTnENsvzp+YpcAV7kCYiXni1v8qZh++lpw4ch4rrwC0u/EZRnBHIehzCGzwXDSQ== + +"@tanstack/query-devtools@5.65.0": + version "5.65.0" + resolved "https://registry.yarnpkg.com/@tanstack/query-devtools/-/query-devtools-5.65.0.tgz#37da5e911543b4f6d98b9a04369eab0de6044ba1" + integrity sha512-g5y7zc07U9D3esMdqUfTEVu9kMHoIaVBsD0+M3LPdAdD710RpTcLiNvJY1JkYXqkq9+NV+CQoemVNpQPBXVsJg== + +"@tanstack/react-query-devtools@5.66.9": + version "5.66.9" + resolved "https://registry.yarnpkg.com/@tanstack/react-query-devtools/-/react-query-devtools-5.66.9.tgz#5cb69b874682289e5014bcf9b6460a2d35df129f" + integrity sha512-70G6AR35he53SYUcUK6EdqNR18zejCv1rM6900gjZP408EAex56YLwVSeijzk9lWeU2J42G9Fjh0i1WngUTsgw== + dependencies: + "@tanstack/query-devtools" "5.65.0" + +"@tanstack/react-query@5.90.10": + version "5.90.10" + resolved "https://registry.yarnpkg.com/@tanstack/react-query/-/react-query-5.90.10.tgz#dc2d4acbe1c06b708ccaeed43a26ad56bc5d1718" + integrity sha512-BKLss9Y8PQ9IUjPYQiv3/Zmlx92uxffUOX8ZZNoQlCIZBJPT5M+GOMQj7xislvVQ6l1BstBjcX0XB/aHfFYVNw== + dependencies: + "@tanstack/query-core" "5.90.10" + +"@tanstack/react-table@8.21.3": + version "8.21.3" + resolved "https://registry.yarnpkg.com/@tanstack/react-table/-/react-table-8.21.3.tgz#2c38c747a5731c1a07174fda764b9c2b1fb5e91b" + integrity sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww== + dependencies: + "@tanstack/table-core" "8.21.3" + +"@tanstack/table-core@8.21.3": + version "8.21.3" + resolved "https://registry.yarnpkg.com/@tanstack/table-core/-/table-core-8.21.3.tgz#2977727d8fc8dfa079112d9f4d4c019110f1732c" + integrity sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg== + +"@tsconfig/node10@^1.0.7": + version "1.0.12" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.12.tgz#be57ceac1e4692b41be9de6be8c32a106636dba4" + integrity sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@tybys/wasm-util@^0.10.0": + version "0.10.1" + resolved "https://registry.yarnpkg.com/@tybys/wasm-util/-/wasm-util-0.10.1.tgz#ecddd3205cf1e2d5274649ff0eedd2991ed7f414" + integrity sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg== + dependencies: + tslib "^2.4.0" + +"@types/argparse@1.0.38": + version "1.0.38" + resolved "https://registry.yarnpkg.com/@types/argparse/-/argparse-1.0.38.tgz#a81fd8606d481f873a3800c6ebae4f1d768a56a9" + integrity sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA== + +"@types/babel__core@^7.1.14", "@types/babel__core@^7.20.5": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== + dependencies: + "@babel/types" "^7.28.2" + +"@types/estree@1.0.8", "@types/estree@^1.0.0", "@types/estree@^1.0.6": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/hoist-non-react-statics@^3.3.6": + version "3.3.7" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz#306e3a3a73828522efa1341159da4846e7573a6c" + integrity sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g== + dependencies: + hoist-non-react-statics "^3.3.0" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@29.5.14": + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/node@*", "@types/node@24.10.1": + version "24.10.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-24.10.1.tgz#91e92182c93db8bd6224fca031e2370cef9a8f01" + integrity sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ== + dependencies: + undici-types "~7.16.0" + +"@types/node@22.10.7": + version "22.10.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.7.tgz#14a1ca33fd0ebdd9d63593ed8d3fbc882a6d28d7" + integrity sha512-V09KvXxFiutGp6B7XkpaDXlNadZxrzajcY50EuoLIpQ6WWYCSvf19lVIazzfIzQvhUN2HjX12spLojTnhuKlGg== + dependencies: + undici-types "~6.20.0" + +"@types/react-dom@19.2.3", "@types/react-dom@^19.1.2": + version "19.2.3" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-19.2.3.tgz#c1e305d15a52a3e508d54dca770d202cb63abf2c" + integrity sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ== + +"@types/react-modal@3.16.3": + version "3.16.3" + resolved "https://registry.yarnpkg.com/@types/react-modal/-/react-modal-3.16.3.tgz#250f32c07f1de28e2bcf9c3e84b56adaa6897013" + integrity sha512-xXuGavyEGaFQDgBv4UVm8/ZsG+qxeQ7f77yNrW3n+1J6XAstUy5rYHeIHPh1KzsGc6IkCIdu6lQ2xWzu1jBTLg== + dependencies: + "@types/react" "*" + +"@types/react@*", "@types/react@^19.1.2": + version "19.2.6" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.6.tgz#d27db1ff45012d53980f5589fda925278e1249ca" + integrity sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w== + dependencies: + csstype "^3.2.2" + +"@types/react@19.2.5": + version "19.2.5" + resolved "https://registry.yarnpkg.com/@types/react/-/react-19.2.5.tgz#bb75da5c52a956ba7d2623dffbba0fdadc3e4145" + integrity sha512-keKxkZMqnDicuvFoJbzrhbtdLSPhj/rZThDlKWCDbgXmUg0rEUFtRssDXKYmtXluZlIqiC5VqkCgRwzuyLHKHw== + dependencies: + csstype "^3.0.2" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.46.4.tgz#005dc4eebcb27462f20de3afe888065f65cec100" + integrity sha512-R48VhmTJqplNyDxCyqqVkFSZIx1qX6PzwqgcXn1olLrzxcSBDlOsbtcnQuQhNtnNiJ4Xe5gREI1foajYaYU2Vg== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.46.4" + "@typescript-eslint/type-utils" "8.46.4" + "@typescript-eslint/utils" "8.46.4" + "@typescript-eslint/visitor-keys" "8.46.4" + graphemer "^1.4.0" + ignore "^7.0.0" + natural-compare "^1.4.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/eslint-plugin@8.47.0", "@typescript-eslint/eslint-plugin@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.47.0.tgz#c53edeec13a79483f4ca79c298d5231b02e9dc17" + integrity sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.47.0" + "@typescript-eslint/type-utils" "8.47.0" + "@typescript-eslint/utils" "8.47.0" + "@typescript-eslint/visitor-keys" "8.47.0" + graphemer "^1.4.0" + ignore "^7.0.0" + natural-compare "^1.4.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/parser@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.46.4.tgz#1a5bfd48be57bc07eec64e090ac46e89f47ade31" + integrity sha512-tK3GPFWbirvNgsNKto+UmB/cRtn6TZfyw0D6IKrW55n6Vbs7KJoZtI//kpTKzE/DUmmnAFD8/Ca46s7Obs92/w== + dependencies: + "@typescript-eslint/scope-manager" "8.46.4" + "@typescript-eslint/types" "8.46.4" + "@typescript-eslint/typescript-estree" "8.46.4" + "@typescript-eslint/visitor-keys" "8.46.4" + debug "^4.3.4" + +"@typescript-eslint/parser@8.47.0", "@typescript-eslint/parser@^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.47.0.tgz#51b14ab2be2057ec0f57073b9ff3a9c078b0a964" + integrity sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ== + dependencies: + "@typescript-eslint/scope-manager" "8.47.0" + "@typescript-eslint/types" "8.47.0" + "@typescript-eslint/typescript-estree" "8.47.0" + "@typescript-eslint/visitor-keys" "8.47.0" + debug "^4.3.4" + +"@typescript-eslint/project-service@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.46.4.tgz#fa9872673b51fb57e5d5da034edbe17424ddd185" + integrity sha512-nPiRSKuvtTN+no/2N1kt2tUh/HoFzeEgOm9fQ6XQk4/ApGqjx0zFIIaLJ6wooR1HIoozvj2j6vTi/1fgAz7UYQ== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.46.4" + "@typescript-eslint/types" "^8.46.4" + debug "^4.3.4" + +"@typescript-eslint/project-service@8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.47.0.tgz#b8afc65e0527568018af911b702dcfbfdca16471" + integrity sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.47.0" + "@typescript-eslint/types" "^8.47.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.46.4.tgz#78c9b4856c0094def64ffa53ea955b46bec13304" + integrity sha512-tMDbLGXb1wC+McN1M6QeDx7P7c0UWO5z9CXqp7J8E+xGcJuUuevWKxuG8j41FoweS3+L41SkyKKkia16jpX7CA== + dependencies: + "@typescript-eslint/types" "8.46.4" + "@typescript-eslint/visitor-keys" "8.46.4" + +"@typescript-eslint/scope-manager@8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.47.0.tgz#d1c36a973a5499fed3a99e2e6a66aec5c9b1e542" + integrity sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg== + dependencies: + "@typescript-eslint/types" "8.47.0" + "@typescript-eslint/visitor-keys" "8.47.0" + +"@typescript-eslint/tsconfig-utils@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.46.4.tgz#989a338093b6b91b0552f1f51331d89ec6980382" + integrity sha512-+/XqaZPIAk6Cjg7NWgSGe27X4zMGqrFqZ8atJsX3CWxH/jACqWnrWI68h7nHQld0y+k9eTTjb9r+KU4twLoo9A== + +"@typescript-eslint/tsconfig-utils@8.47.0", "@typescript-eslint/tsconfig-utils@^8.46.4", "@typescript-eslint/tsconfig-utils@^8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.47.0.tgz#4f178b62813538759e0989dd081c5474fad39b84" + integrity sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g== + +"@typescript-eslint/type-utils@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.46.4.tgz#ae71b428a3c138b5084affe47893c129949171e0" + integrity sha512-V4QC8h3fdT5Wro6vANk6eojqfbv5bpwHuMsBcJUJkqs2z5XnYhJzyz9Y02eUmF9u3PgXEUiOt4w4KHR3P+z0PQ== + dependencies: + "@typescript-eslint/types" "8.46.4" + "@typescript-eslint/typescript-estree" "8.46.4" + "@typescript-eslint/utils" "8.46.4" + debug "^4.3.4" + ts-api-utils "^2.1.0" + +"@typescript-eslint/type-utils@8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.47.0.tgz#b9b0141d99bd5bece3811d7eee68a002597ffa55" + integrity sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A== + dependencies: + "@typescript-eslint/types" "8.47.0" + "@typescript-eslint/typescript-estree" "8.47.0" + "@typescript-eslint/utils" "8.47.0" + debug "^4.3.4" + ts-api-utils "^2.1.0" + +"@typescript-eslint/types@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.46.4.tgz#38022bfda051be80e4120eeefcd2b6e3e630a69b" + integrity sha512-USjyxm3gQEePdUwJBFjjGNG18xY9A2grDVGuk7/9AkjIF1L+ZrVnwR5VAU5JXtUnBL/Nwt3H31KlRDaksnM7/w== + +"@typescript-eslint/types@8.47.0", "@typescript-eslint/types@^8.46.4", "@typescript-eslint/types@^8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.47.0.tgz#c7fc9b6642d03505f447a8392934b9d1850de5af" + integrity sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A== + +"@typescript-eslint/typescript-estree@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.46.4.tgz#6a9eeab0da45bf400f22c818e0f47102a980ceaa" + integrity sha512-7oV2qEOr1d4NWNmpXLR35LvCfOkTNymY9oyW+lUHkmCno7aOmIf/hMaydnJBUTBMRCOGZh8YjkFOc8dadEoNGA== + dependencies: + "@typescript-eslint/project-service" "8.46.4" + "@typescript-eslint/tsconfig-utils" "8.46.4" + "@typescript-eslint/types" "8.46.4" + "@typescript-eslint/visitor-keys" "8.46.4" + 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" + +"@typescript-eslint/typescript-estree@8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.47.0.tgz#86416dad58db76c4b3bd6a899b1381f9c388489a" + integrity sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg== + dependencies: + "@typescript-eslint/project-service" "8.47.0" + "@typescript-eslint/tsconfig-utils" "8.47.0" + "@typescript-eslint/types" "8.47.0" + "@typescript-eslint/visitor-keys" "8.47.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" + +"@typescript-eslint/utils@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.46.4.tgz#ea7878ddd625948cad4424dc2752b1be236556f5" + integrity sha512-AbSv11fklGXV6T28dp2Me04Uw90R2iJ30g2bgLz529Koehrmkbs1r7paFqr1vPCZi7hHwYxYtxfyQMRC8QaVSg== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.46.4" + "@typescript-eslint/types" "8.46.4" + "@typescript-eslint/typescript-estree" "8.46.4" + +"@typescript-eslint/utils@8.47.0", "@typescript-eslint/utils@^8.18.1", "@typescript-eslint/utils@^8.44.1": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.47.0.tgz#d6c30690431dbfdab98fc027202af12e77c91419" + integrity sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.47.0" + "@typescript-eslint/types" "8.47.0" + "@typescript-eslint/typescript-estree" "8.47.0" + +"@typescript-eslint/visitor-keys@8.46.4": + version "8.46.4" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.46.4.tgz#07031bd8d3ca6474e121221dae1055daead888f1" + integrity sha512-/++5CYLQqsO9HFGLI7APrxBJYo+5OCMpViuhV8q5/Qa3o5mMrF//eQHks+PXcsAVaLdn817fMuS7zqoXNNZGaw== + dependencies: + "@typescript-eslint/types" "8.46.4" + eslint-visitor-keys "^4.2.1" + +"@typescript-eslint/visitor-keys@8.47.0": + version "8.47.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.47.0.tgz#35f36ed60a170dfc9d4d738e78387e217f24c29f" + integrity sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ== + dependencies: + "@typescript-eslint/types" "8.47.0" + eslint-visitor-keys "^4.2.1" + +"@unrs/resolver-binding-android-arm-eabi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz#9f5b04503088e6a354295e8ea8fe3cb99e43af81" + integrity sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw== + +"@unrs/resolver-binding-android-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz#7414885431bd7178b989aedc4d25cccb3865bc9f" + integrity sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g== + +"@unrs/resolver-binding-darwin-arm64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz#b4a8556f42171fb9c9f7bac8235045e82aa0cbdf" + integrity sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g== + +"@unrs/resolver-binding-darwin-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz#fd4d81257b13f4d1a083890a6a17c00de571f0dc" + integrity sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ== + +"@unrs/resolver-binding-freebsd-x64@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz#d2513084d0f37c407757e22f32bd924a78cfd99b" + integrity sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw== + +"@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz#844d2605d057488d77fab09705f2866b86164e0a" + integrity sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw== + +"@unrs/resolver-binding-linux-arm-musleabihf@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz#204892995cefb6bd1d017d52d097193bc61ddad3" + integrity sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw== + +"@unrs/resolver-binding-linux-arm64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz#023eb0c3aac46066a10be7a3f362e7b34f3bdf9d" + integrity sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ== + +"@unrs/resolver-binding-linux-arm64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz#9e6f9abb06424e3140a60ac996139786f5d99be0" + integrity sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w== + +"@unrs/resolver-binding-linux-ppc64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz#b111417f17c9d1b02efbec8e08398f0c5527bb44" + integrity sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA== + +"@unrs/resolver-binding-linux-riscv64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz#92ffbf02748af3e99873945c9a8a5ead01d508a9" + integrity sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ== + +"@unrs/resolver-binding-linux-riscv64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz#0bec6f1258fc390e6b305e9ff44256cb207de165" + integrity sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew== + +"@unrs/resolver-binding-linux-s390x-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz#577843a084c5952f5906770633ccfb89dac9bc94" + integrity sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg== + +"@unrs/resolver-binding-linux-x64-gnu@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz#36fb318eebdd690f6da32ac5e0499a76fa881935" + integrity sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w== + +"@unrs/resolver-binding-linux-x64-musl@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz#bfb9af75f783f98f6a22c4244214efe4df1853d6" + integrity sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA== + +"@unrs/resolver-binding-wasm32-wasi@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz#752c359dd875684b27429500d88226d7cc72f71d" + integrity sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ== + dependencies: + "@napi-rs/wasm-runtime" "^0.2.11" + +"@unrs/resolver-binding-win32-arm64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz#ce5735e600e4c2fbb409cd051b3b7da4a399af35" + integrity sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw== + +"@unrs/resolver-binding-win32-ia32-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz#72fc57bc7c64ec5c3de0d64ee0d1810317bc60a6" + integrity sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ== + +"@unrs/resolver-binding-win32-x64-msvc@1.11.1": + version "1.11.1" + resolved "https://registry.yarnpkg.com/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz#538b1e103bf8d9864e7b85cc96fa8d6fb6c40777" + integrity sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g== + +"@viselect/react@3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@viselect/react/-/react-3.9.0.tgz#d37bbb33d1759d625ba3be219ac299ddb9e67ccd" + integrity sha512-uz3ehdawjXwTUGnDKyNfmecviLAjUIG7cOQdeKcdXiSCHg9ZS12Vhr/j0shuHjX0xPvy9IqlbVuvzOHq77QDQw== + dependencies: + "@viselect/vanilla" "3.9.0" + +"@viselect/vanilla@3.9.0": + version "3.9.0" + resolved "https://registry.yarnpkg.com/@viselect/vanilla/-/vanilla-3.9.0.tgz#bddadfa2726ab9590edfe42dac0cd8e5cb01fd4e" + integrity sha512-E9eBgoi/crJ0SlZMAc+Yst7nU324LZ5LLvcXjzWEcrfllscdpTml2OLOKHC7O8Bbz19OybSLv6VexxnjlJrLxQ== + +"@vitejs/plugin-react-swc@4.2.2": + version "4.2.2" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react-swc/-/plugin-react-swc-4.2.2.tgz#9818ed54318dcb0f254f6322c6bfbd0fcec2b087" + integrity sha512-x+rE6tsxq/gxrEJN3Nv3dIV60lFflPj94c90b+NNo6n1QV1QQUTLoL0MpaOVasUZ0zqVBn7ead1B5ecx1JAGfA== + dependencies: + "@rolldown/pluginutils" "1.0.0-beta.47" + "@swc/core" "^1.13.5" + +"@vitejs/plugin-react@^5.0.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@vitejs/plugin-react/-/plugin-react-5.1.1.tgz#fa1957e053fe90d7cc2deea5593ae382a9761595" + integrity sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA== + dependencies: + "@babel/core" "^7.28.5" + "@babel/plugin-transform-react-jsx-self" "^7.27.1" + "@babel/plugin-transform-react-jsx-source" "^7.27.1" + "@rolldown/pluginutils" "1.0.0-beta.47" + "@types/babel__core" "^7.20.5" + react-refresh "^0.18.0" + +"@volar/language-core@2.4.23", "@volar/language-core@~2.4.11": + version "2.4.23" + resolved "https://registry.yarnpkg.com/@volar/language-core/-/language-core-2.4.23.tgz#deb6dbc5fdbafa9bb7ba691fc59cb196cdb856d3" + integrity sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ== + dependencies: + "@volar/source-map" "2.4.23" + +"@volar/source-map@2.4.23": + version "2.4.23" + resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-2.4.23.tgz#d476e11a3a669d89858a5eb38b02342be39b0e44" + integrity sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q== + +"@volar/typescript@^2.4.11": + version "2.4.23" + resolved "https://registry.yarnpkg.com/@volar/typescript/-/typescript-2.4.23.tgz#b9b114ea01ad0ad977139edda0239fdafdb21ad7" + integrity sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag== + dependencies: + "@volar/language-core" "2.4.23" + path-browserify "^1.0.1" + vscode-uri "^3.0.8" + +"@vue/compiler-core@3.5.24": + version "3.5.24" + resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.5.24.tgz#1853f4b7d7090033cd9041aab6e7e8017d66c39c" + integrity sha512-eDl5H57AOpNakGNAkFDH+y7kTqrQpJkZFXhWZQGyx/5Wh7B1uQYvcWkvZi11BDhscPgj8N7XV3oRwiPnx1Vrig== + dependencies: + "@babel/parser" "^7.28.5" + "@vue/shared" "3.5.24" + entities "^4.5.0" + estree-walker "^2.0.2" + source-map-js "^1.2.1" + +"@vue/compiler-dom@^3.5.0": + version "3.5.24" + resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.5.24.tgz#b02e98749c377d6d2ba30dc2e94ce0f5b0af060c" + integrity sha512-1QHGAvs53gXkWdd3ZMGYuvQFXHW4ksKWPG8HP8/2BscrbZ0brw183q2oNWjMrSWImYLHxHrx1ItBQr50I/q2zw== + dependencies: + "@vue/compiler-core" "3.5.24" + "@vue/shared" "3.5.24" + +"@vue/compiler-vue2@^2.7.16": + version "2.7.16" + resolved "https://registry.yarnpkg.com/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz#2ba837cbd3f1b33c2bc865fbe1a3b53fb611e249" + integrity sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A== + dependencies: + de-indent "^1.0.2" + he "^1.2.0" + +"@vue/language-core@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@vue/language-core/-/language-core-2.2.0.tgz#e48c54584f889f78b120ce10a050dfb316c7fcdf" + integrity sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw== + dependencies: + "@volar/language-core" "~2.4.11" + "@vue/compiler-dom" "^3.5.0" + "@vue/compiler-vue2" "^2.7.16" + "@vue/shared" "^3.5.0" + alien-signals "^0.4.9" + minimatch "^9.0.3" + muggle-string "^0.4.1" + path-browserify "^1.0.1" + +"@vue/shared@3.5.24", "@vue/shared@^3.5.0": + version "3.5.24" + resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.5.24.tgz#45ea9e6e037e53cfb8141ffa6bcad75b8be11e9c" + integrity sha512-9cwHL2EsJBdi8NY22pngYYWzkTDhld6fAD6jlaeloNGciNSJL6bLpbxVgXl96X00Jtc6YWQv96YA/0sxex/k1A== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.15.0, acorn@^8.4.1: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +ajv-draft-04@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz#3b64761b268ba0b9e668f0b41ba53fce0ad77fc8" + integrity sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw== + +ajv-formats@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== + dependencies: + ajv "^8.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.0: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ajv@~8.12.0: + version "8.12.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.12.0.tgz#d1a0527323e22f53562c567c00991577dfbe19d1" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ajv@~8.13.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.13.0.tgz#a3939eaec9fb80d217ddf0c3376948c023f28c91" + integrity sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA== + dependencies: + fast-deep-equal "^3.1.3" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.4.1" + +alien-signals@^0.4.9: + version "0.4.14" + resolved "https://registry.yarnpkg.com/alien-signals/-/alien-signals-0.4.14.tgz#9ff8f72a272300a51692f54bd9bbbada78fbf539" + integrity sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7, argparse@~1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-hidden@^1.2.4: + version "1.2.6" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.2.6.tgz#73051c9b088114c795b1ea414e9c0fff874ffc1a" + integrity sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA== + dependencies: + tslib "^2.0.0" + +aria-query@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.2.tgz#93f81a43480e33a338f19163a3d10a50c01dcd59" + integrity sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw== + +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + +array-includes@^3.1.6, array-includes@^3.1.8, array-includes@^3.1.9: + version "3.1.9" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.9.tgz#1f0ccaa08e90cdbc3eb433210f903ad0f17c3f3a" + integrity sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.24.0" + es-object-atoms "^1.1.1" + get-intrinsic "^1.3.0" + is-string "^1.1.1" + math-intrinsics "^1.1.0" + +array.prototype.findlast@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz#3e4fbcb30a15a7f5bf64cf2faae22d139c2e4904" + integrity sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.findlastindex@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz#cfa1065c81dcb64e34557c9b81d012f6a421c564" + integrity sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-shim-unscopables "^1.1.0" + +array.prototype.flat@^1.3.1, array.prototype.flat@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.2, array.prototype.flatmap@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.tosorted@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz#fe954678ff53034e717ea3352a03f0b0b86f7ffc" + integrity sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + +ast-types-flow@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.8.tgz#0a85e1c92695769ac13a428bb653e7538bea27d6" + integrity sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ== + +async-function@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/async-function/-/async-function-1.0.0.tgz#509c9fca60eaf85034c6829838188e4e4c8ffb2b" + integrity sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA== + +async@^3.2.6: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + +attr-accept@^2.2.4: + version "2.2.5" + resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.5.tgz#d7061d958e6d4f97bf8665c68b75851a0713ab5e" + integrity sha512-0bDNnY/u6pPwHDMoF0FieU354oBi0a8rD9FcsLwzcGWbc8KS8KPIi7y+s13OlVY+gMWc/9xEMUgNE6Qm8ZllYQ== + +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + +axe-core@^4.10.0: + version "4.11.0" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.11.0.tgz#16f74d6482e343ff263d4f4503829e9ee91a86b6" + integrity sha512-ilYanEU8vxxBexpJd8cWM4ElSQq4QctCLKih0TSfjIfCQTeyH/6zVrmIJfLPrKTKJRbiG+cfnZbQIjAlJmF1jQ== + +axobject-query@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.1.0.tgz#28768c76d0e3cff21bc62a9e2d0b6ac30042a1ee" + integrity sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +baseline-browser-mapping@^2.8.25: + version "2.8.29" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.8.29.tgz#d8800b71399c783cb1bf2068c2bcc3b6cfd7892c" + integrity sha512-sXdt2elaVnhpDNRDz+1BDx1JQoJRuNk7oVlAlbGiFkLikHCAQiccexF/9e91zVi6RCgqspl04aP+6Cnl9zRLrA== + +brace-expansion@^1.1.7: + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.28.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.0.tgz#9cefece0a386a17a3cd3d22ebf67b9deca1b5929" + integrity sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ== + dependencies: + baseline-browser-mapping "^2.8.25" + caniuse-lite "^1.0.30001754" + electron-to-chromium "^1.5.249" + node-releases "^2.0.27" + update-browserslist-db "^1.1.4" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +call-bind-apply-helpers@^1.0.0, call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.7, call-bind@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.8.tgz#0736a9660f537e3388826f440d5ec45f744eaa4c" + integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== + dependencies: + call-bind-apply-helpers "^1.0.0" + es-define-property "^1.0.0" + get-intrinsic "^1.2.4" + set-function-length "^1.2.2" + +call-bound@^1.0.2, call-bound@^1.0.3, call-bound@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001579, caniuse-lite@^1.0.30001754: + version "1.0.30001756" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001756.tgz#fe80104631102f88e58cad8aa203a2c3e5ec9ebd" + integrity sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A== + +chalk@4.1.2, chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-4.0.3.tgz#7be37a4c03c9aee1ecfe862a4a23b2c70c205d30" + integrity sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA== + dependencies: + readdirp "^4.0.1" + +chromatic@11.28.2: + version "11.28.2" + resolved "https://registry.yarnpkg.com/chromatic/-/chromatic-11.28.2.tgz#c0b9f59dcc323ca8bf2c2790f3c9e3d285834efb" + integrity sha512-aCmUPcZUs4/p9zRZdMreOoO/5JqO2DiJC3md1/vRx8dlMRcmR/YI5ZbgXZcai2absVR+6hsXZ5XiPxV2sboTuQ== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + +classnames@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" + integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== + +client-only@0.0.1, client-only@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1" + integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clsx@2.1.1, clsx@^2.0.0, clsx@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-2.1.1.tgz#eed397c9fd8bd882bfb18deab7102049a2f32999" + integrity sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA== + +cmdk@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cmdk/-/cmdk-1.0.4.tgz#cbddef6f5ade2378f85c80a0b9ad9a8a712779b5" + integrity sha512-AnsjfHyHpQ/EFeAnG216WY7A5LiYCoZzCSygiLvfXC3H3LFGCprErteUcszaVluGOhuOTbJS3jWHrSDYPBBygg== + dependencies: + "@radix-ui/react-dialog" "^1.1.2" + "@radix-ui/react-id" "^1.1.0" + "@radix-ui/react-primitive" "^2.0.0" + use-sync-external-store "^1.2.2" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + +compare-versions@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.1.tgz#7af3cc1099ba37d244b3145a9af5201b629148a9" + integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== + +compute-scroll-into-view@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-3.1.1.tgz#02c3386ec531fb6a9881967388e53e8564f3e9aa" + integrity sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +confbox@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.1.8.tgz#820d73d3b3c82d9bd910652c5d4d599ef8ff8b06" + integrity sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w== + +confbox@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/confbox/-/confbox-0.2.2.tgz#8652f53961c74d9e081784beed78555974a9c110" + integrity sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +core-js@^3, core-js@^3.38.1: + version "3.47.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.47.0.tgz#436ef07650e191afeb84c24481b298bd60eb4a17" + integrity sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +csstype@^3.0.2, csstype@^3.2.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + +damerau-levenshtein@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + integrity sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg== + +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.4.0: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +decimal.js@^10.4.3: + version "10.6.0" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.6.0.tgz#e649a43e3ab953a72192ff5983865e509f37ed9a" + integrity sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg== + +dedent@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.0.tgz#c1f9445335f0175a96587be245a282ff451446ca" + integrity sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@4.3.1, deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +detect-libc@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +diff@~8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-8.0.2.tgz#712156a6dd288e66ebb986864e190c2fc9eddfae" + integrity sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg== + +dnd-core@14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/dnd-core/-/dnd-core-14.0.1.tgz#76d000e41c494983210fb20a48b835f81a203c2e" + integrity sha512-+PVS2VPTgKFPYWo3vAFEA8WPbTf7/xo43TifH9G8S1KqnrQu0o77A3unrF5yOugy4mIz7K5wAVFHUcha7wsz6A== + dependencies: + "@react-dnd/asap" "^4.0.0" + "@react-dnd/invariant" "^2.0.0" + redux "^4.1.1" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +downshift@9.0.9: + version "9.0.9" + resolved "https://registry.yarnpkg.com/downshift/-/downshift-9.0.9.tgz#fd683a376a21bcc52f0d13d6cda47b4ea521f62b" + integrity sha512-ygOT8blgiz5liDuEFAIaPeU4dDEa+w9p6PHVUisPIjrkF5wfR59a52HpGWAVVMoWnoFO8po2mZSScKZueihS7g== + dependencies: + "@babel/runtime" "^7.24.5" + compute-scroll-into-view "^3.1.0" + prop-types "^15.8.1" + react-is "18.2.0" + tslib "^2.6.2" + +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.5.249: + version "1.5.256" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.256.tgz#f07f78de0893ab060f60ac897195c029a3b50d1a" + integrity sha512-uqYq1IQhpXXLX+HgiXdyOZml7spy4xfy42yPxcCCRjswp0fYM2X+JwCON07lqnpLEGVCj739B7Yr+FngmHBMEQ== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +entities@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + +error-ex@^1.3.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== + dependencies: + is-arrayish "^0.2.1" + +es-abstract@^1.17.5, es-abstract@^1.23.2, es-abstract@^1.23.3, es-abstract@^1.23.5, es-abstract@^1.23.6, es-abstract@^1.23.9, es-abstract@^1.24.0: + version "1.24.0" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.24.0.tgz#c44732d2beb0acc1ed60df840869e3106e7af328" + integrity sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + es-set-tostringtag "^2.1.0" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.3.0" + get-proto "^1.0.1" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-negative-zero "^2.0.3" + is-regex "^1.2.1" + is-set "^2.0.3" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.1" + math-intrinsics "^1.1.0" + object-inspect "^1.13.4" + object-keys "^1.1.1" + object.assign "^4.1.7" + own-keys "^1.0.1" + regexp.prototype.flags "^1.5.4" + safe-array-concat "^1.1.3" + safe-push-apply "^1.0.0" + safe-regex-test "^1.1.0" + set-proto "^1.0.0" + stop-iteration-iterator "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.19" + +es-define-property@^1.0.0, es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-iterator-helpers@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz#d1dd0f58129054c0ad922e6a9a1e65eef435fe75" + integrity sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-set-tostringtag "^2.0.3" + function-bind "^1.1.2" + get-intrinsic "^1.2.6" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + iterator.prototype "^1.1.4" + safe-array-concat "^1.1.3" + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3, es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +es-shim-unscopables@^1.0.2, es-shim-unscopables@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz#438df35520dac5d105f3943d927549ea3b00f4b5" + integrity sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw== + dependencies: + hasown "^2.0.2" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + +esbuild@^0.25.0: + version "0.25.12" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.25.12.tgz#97a1d041f4ab00c2fce2f838d2b9969a2d2a97a5" + integrity sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg== + optionalDependencies: + "@esbuild/aix-ppc64" "0.25.12" + "@esbuild/android-arm" "0.25.12" + "@esbuild/android-arm64" "0.25.12" + "@esbuild/android-x64" "0.25.12" + "@esbuild/darwin-arm64" "0.25.12" + "@esbuild/darwin-x64" "0.25.12" + "@esbuild/freebsd-arm64" "0.25.12" + "@esbuild/freebsd-x64" "0.25.12" + "@esbuild/linux-arm" "0.25.12" + "@esbuild/linux-arm64" "0.25.12" + "@esbuild/linux-ia32" "0.25.12" + "@esbuild/linux-loong64" "0.25.12" + "@esbuild/linux-mips64el" "0.25.12" + "@esbuild/linux-ppc64" "0.25.12" + "@esbuild/linux-riscv64" "0.25.12" + "@esbuild/linux-s390x" "0.25.12" + "@esbuild/linux-x64" "0.25.12" + "@esbuild/netbsd-arm64" "0.25.12" + "@esbuild/netbsd-x64" "0.25.12" + "@esbuild/openbsd-arm64" "0.25.12" + "@esbuild/openbsd-x64" "0.25.12" + "@esbuild/openharmony-arm64" "0.25.12" + "@esbuild/sunos-x64" "0.25.12" + "@esbuild/win32-arm64" "0.25.12" + "@esbuild/win32-ia32" "0.25.12" + "@esbuild/win32-x64" "0.25.12" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-next@15.1.7: + version "15.1.7" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-15.1.7.tgz#80d287e6d1c0742304de8fe57cbc45000c455c11" + integrity sha512-zXoMnYUIy3XHaAoOhrcYkT9UQWvXqWju2K7NNsmb5wd/7XESDwof61eUdW4QhERr3eJ9Ko/vnXqIrj8kk/drYw== + dependencies: + "@next/eslint-plugin-next" "15.1.7" + "@rushstack/eslint-patch" "^1.10.3" + "@typescript-eslint/eslint-plugin" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser" "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0" + eslint-import-resolver-node "^0.3.6" + eslint-import-resolver-typescript "^3.5.2" + eslint-plugin-import "^2.31.0" + eslint-plugin-jsx-a11y "^6.10.0" + eslint-plugin-react "^7.37.0" + eslint-plugin-react-hooks "^5.0.0" + +eslint-config-prettier@10.1.8: + version "10.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97" + integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== + +eslint-import-resolver-node@^0.3.6, eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.5.2: + version "3.10.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz#23dac32efa86a88e2b8232eb244ac499ad636db2" + integrity sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.4.0" + get-tsconfig "^4.10.0" + is-bun-module "^2.0.0" + stable-hash "^0.0.5" + tinyglobby "^0.2.13" + unrs-resolver "^1.6.2" + +eslint-module-utils@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz#f76d3220bfb83c057651359295ab5854eaad75ff" + integrity sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw== + dependencies: + debug "^3.2.7" + +eslint-plugin-import@^2.31.0: + version "2.32.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz#602b55faa6e4caeaa5e970c198b5c00a37708980" + integrity sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.9" + array.prototype.findlastindex "^1.2.6" + array.prototype.flat "^1.3.3" + array.prototype.flatmap "^1.3.3" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.1" + hasown "^2.0.2" + is-core-module "^2.16.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.1" + semver "^6.3.1" + string.prototype.trimend "^1.0.9" + tsconfig-paths "^3.15.0" + +eslint-plugin-jsx-a11y@6.10.2, eslint-plugin-jsx-a11y@^6.10.0: + version "6.10.2" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz#d2812bb23bf1ab4665f1718ea442e8372e638483" + integrity sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q== + dependencies: + aria-query "^5.3.2" + array-includes "^3.1.8" + array.prototype.flatmap "^1.3.2" + ast-types-flow "^0.0.8" + axe-core "^4.10.0" + axobject-query "^4.1.0" + damerau-levenshtein "^1.0.8" + emoji-regex "^9.2.2" + hasown "^2.0.2" + jsx-ast-utils "^3.3.5" + language-tags "^1.0.9" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + safe-regex-test "^1.0.3" + string.prototype.includes "^2.0.1" + +eslint-plugin-react-hooks@7.0.1, eslint-plugin-react-hooks@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz#66e258db58ece50723ef20cc159f8aa908219169" + integrity sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA== + dependencies: + "@babel/core" "^7.24.4" + "@babel/parser" "^7.24.4" + hermes-parser "^0.25.1" + zod "^3.25.0 || ^4.0.0" + zod-validation-error "^3.5.0 || ^4.0.0" + +eslint-plugin-react-hooks@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz#1be0080901e6ac31ce7971beed3d3ec0a423d9e3" + integrity sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg== + +eslint-plugin-react-refresh@0.4.24, eslint-plugin-react-refresh@^0.4.19: + version "0.4.24" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.24.tgz#6914e8757eb7d7ccc3efb9dbcc8a51feda71d89e" + integrity sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w== + +eslint-plugin-react@^7.37.0: + version "7.37.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz#2975511472bdda1b272b34d779335c9b0e877065" + integrity sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA== + dependencies: + array-includes "^3.1.8" + array.prototype.findlast "^1.2.5" + array.prototype.flatmap "^1.3.3" + array.prototype.tosorted "^1.1.4" + doctrine "^2.1.0" + es-iterator-helpers "^1.2.1" + estraverse "^5.3.0" + hasown "^2.0.2" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.9" + object.fromentries "^2.0.8" + object.values "^1.2.1" + prop-types "^15.8.1" + resolve "^2.0.0-next.5" + semver "^6.3.1" + string.prototype.matchall "^4.0.12" + string.prototype.repeat "^1.0.0" + +eslint-scope@^8.2.0, eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.0, eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@9.20.1: + version "9.20.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6" + integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.11.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.20.0" + "@eslint/plugin-kit" "^0.2.5" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.1" + "@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.2.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" + +eslint@9.39.1, eslint@^9.25.0: + version "9.39.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.1.tgz#be8bf7c6de77dcc4252b5a8dcb31c2efff74a6e5" + integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.21.1" + "@eslint/config-helpers" "^0.4.2" + "@eslint/core" "^0.17.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.39.1" + "@eslint/plugin-kit" "^0.4.1" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0, espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== + dependencies: + acorn "^8.15.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.1" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exenv@^1.2.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" + integrity sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw== + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +exsolve@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/exsolve/-/exsolve-1.0.8.tgz#7f5e34da61cd1116deda5136e62292c096f50613" + integrity sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA== + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.1.tgz#784b4e897340f3dbbef17413b3f11acf03c874c4" + integrity sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg== + 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.4" + +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + 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" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fast-uri@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.0.tgz#66eecff6c764c0df9b762e62ca7edcfb53b4edfa" + integrity sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA== + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fdir@^6.4.4, fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +fflate@^0.4.8: + version "0.4.8" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae" + integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA== + +figlet@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.8.1.tgz#e8e8a07e8c16be24c31086d7d5de8a9b9cf7f0fd" + integrity sha512-kEC3Sme+YvA8Hkibv0NR1oClGcWia0VB2fC1SlMy027cwe795Xx40Xiv/nw/iFAwQLupymWh+uhAAErn/7hwPg== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +file-selector@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/file-selector/-/file-selector-2.1.2.tgz#fe7c7ee9e550952dfbc863d73b14dc740d7de8b4" + integrity sha512-QgXo+mXTe8ljeqUFaX3QVHc5osSItJ/Km+xpocx0aSqWGMSCf6qYs/VnzZgS864Pjn5iceMRFigeAV7AfTlaig== + dependencies: + tslib "^2.7.0" + +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +for-each@^0.3.3, for-each@^0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.5.tgz#d650688027826920feeb0af747ee7b9421a41d47" + integrity sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg== + dependencies: + is-callable "^1.2.7" + +fs-extra@~11.3.0: + version "11.3.2" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-11.3.2.tgz#c838aeddc6f4a8c74dd15f85e11fe5511bfe02a4" + integrity sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +fsevents@^2.3.2, fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + +generator-function@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/generator-function/-/generator-function-2.0.1.tgz#0e75dd410d1243687a0ba2e951b94eedb8f737a2" + integrity sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.2.4, get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.2.7, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + 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" + +get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-proto@^1.0.0, get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + +get-tsconfig@^4.10.0: + version "4.13.0" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.13.0.tgz#fcdd991e6d22ab9a600f00e91c318707a5d9a0d7" + integrity sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + 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" + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +globals@^16.0.0: + version "16.5.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-16.5.0.tgz#ccf1594a437b97653b2be13ed4d8f5c9f850cac1" + integrity sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ== + +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +gopd@^1.0.1, gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + +has-symbols@^1.0.3, has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +hermes-estree@0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-estree/-/hermes-estree-0.25.1.tgz#6aeec17d1983b4eabf69721f3aa3eb705b17f480" + integrity sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw== + +hermes-parser@^0.25.1: + version "0.25.1" + resolved "https://registry.yarnpkg.com/hermes-parser/-/hermes-parser-0.25.1.tgz#5be0e487b2090886c62bd8a11724cd766d5f54d1" + integrity sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA== + dependencies: + hermes-estree "0.25.1" + +hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +i18next-browser-languagedetector@8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.2.0.tgz#c3ca311e249d2f7d8bb9b3b13ac9af380a3b15b0" + integrity sha512-P+3zEKLnOF0qmiesW383vsLdtQVyKtCNA9cjSoKCppTKPQVfKd2W8hbVo5ZhNJKDqeM7BOcvNoKJOjpHh4Js9g== + dependencies: + "@babel/runtime" "^7.23.2" + +i18next-fs-backend@^2.6.0: + version "2.6.1" + resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-2.6.1.tgz#bb352278136f47599783308df29f0a1b6a0d08b6" + integrity sha512-eYWTX7QT7kJ0sZyCPK6x1q+R63zvNKv2D6UdbMf15A8vNb2ZLyw4NNNZxPFwXlIv/U+oUtg8SakW6ZgJZcoqHQ== + +i18next@25.6.2: + version "25.6.2" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-25.6.2.tgz#d6de1a4be58242c7f0f1436ab2fa66c8f87b2e29" + integrity sha512-0GawNyVUw0yvJoOEBq1VHMAsqdM23XrHkMtl2gKEjviJQSLVXsrPqsoYAxBEugW5AB96I2pZkwRxyl8WZVoWdw== + dependencies: + "@babel/runtime" "^7.27.6" + +ignore@^5.2.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +ignore@^7.0.0: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + +immutable@^5.0.2: + version "5.1.4" + resolved "https://registry.yarnpkg.com/immutable/-/immutable-5.1.4.tgz#e3f8c1fe7b567d56cf26698f31918c241dae8c1f" + integrity sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-lazy@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + +intl-messageformat@^10.1.0: + version "10.7.18" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-10.7.18.tgz#51a6f387afbca9b0f881b2ec081566db8c540b0d" + integrity sha512-m3Ofv/X/tV8Y3tHXLohcuVuhWKo7BBq62cqY15etqmLxg2DZ34AGGgQDeR+SCta2+zICb1NX83af0GJmbQ1++g== + dependencies: + "@formatjs/ecma402-abstract" "2.3.6" + "@formatjs/fast-memoize" "2.2.7" + "@formatjs/icu-messageformat-parser" "2.11.4" + tslib "^2.8.0" + +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-async-function@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.1.1.tgz#3e69018c8e04e73b738793d020bfe884b9fd3523" + integrity sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ== + dependencies: + async-function "^1.0.0" + call-bound "^1.0.3" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-boolean-object@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.2.tgz#7067f47709809a393c71ff5bb3e135d8a9215d9e" + integrity sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-bun-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-2.0.0.tgz#4d7859a87c0fcac950c95e666730e745eae8bddd" + integrity sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ== + dependencies: + semver "^7.7.1" + +is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.16.1: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-generator-function@^1.0.10: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.1.2.tgz#ae3b61e3d5ea4e4839b90bad22b02335051a17d5" + integrity sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA== + dependencies: + call-bound "^1.0.4" + generator-function "^2.0.0" + get-proto "^1.0.1" + has-tostringtag "^1.0.2" + safe-regex-test "^1.1.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.1.tgz#eea430182be8d64174bd96bffbc46f21bf3f9293" + integrity sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew== + dependencies: + call-bound "^1.0.3" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + 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" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + 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" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +iterator.prototype@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/iterator.prototype/-/iterator.prototype-1.1.5.tgz#12c959a29de32de0aa3bbbb801f4d777066dae39" + integrity sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g== + dependencies: + define-data-property "^1.1.4" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + get-proto "^1.0.0" + has-symbols "^1.1.0" + set-function-name "^2.0.2" + +jake@^10.8.5: + version "10.9.4" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.4.tgz#d626da108c63d5cfb00ab5c25fadc7e0084af8e6" + integrity sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA== + dependencies: + async "^3.2.6" + filelist "^1.0.4" + picocolors "^1.1.1" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +jju@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jju/-/jju-1.4.0.tgz#a3abe2718af241a2b2904f84a625970f389ae32a" + integrity sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA== + +"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonfile@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" + integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +"jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5: + version "3.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a" + integrity sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ== + dependencies: + array-includes "^3.1.6" + array.prototype.flat "^1.3.1" + object.assign "^4.1.4" + object.values "^1.1.6" + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +kolorist@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/kolorist/-/kolorist-1.8.0.tgz#edddbbbc7894bc13302cdf740af6374d4a04743c" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +language-subtag-registry@^0.3.20: + version "0.3.23" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz#23529e04d9e3b74679d70142df3fd2eb6ec572e7" + integrity sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ== + +language-tags@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.9.tgz#1ffdcd0ec0fafb4b1be7f8b11f306ad0f9c08777" + integrity sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA== + dependencies: + language-subtag-registry "^0.3.20" + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +local-pkg@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-1.1.2.tgz#c03d208787126445303f8161619dc701afa4abb5" + integrity sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A== + dependencies: + mlly "^1.7.4" + pkg-types "^2.3.0" + quansync "^0.2.11" + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash@~4.17.15: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +loose-envify@^1.0.0, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.30.17: + version "0.30.21" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1, make-error@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +"memoize-one@>=3.1.1 <6": + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@10.0.3: + version "10.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.3.tgz#cf7a0314a16c4d9ab73a7730a0e8e3c3502d47aa" + integrity sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw== + dependencies: + "@isaacs/brace-expansion" "^5.0.0" + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.3, minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mlly@^1.7.4: + version "1.8.0" + resolved "https://registry.yarnpkg.com/mlly/-/mlly-1.8.0.tgz#e074612b938af8eba1eaf43299cbc89cb72d824e" + integrity sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g== + dependencies: + acorn "^8.15.0" + pathe "^2.0.3" + pkg-types "^1.3.1" + ufo "^1.6.1" + +ms@^2.1.1, ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +muggle-string@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/muggle-string/-/muggle-string-0.4.1.tgz#3b366bd43b32f809dc20659534dd30e7c8a0d328" + integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ== + +nanoid@^3.3.11, nanoid@^3.3.6: + version "3.3.11" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.11.tgz#4f4f112cefbe303202f2199838128936266d185b" + integrity sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w== + +napi-postinstall@^0.3.0: + version "0.3.4" + resolved "https://registry.yarnpkg.com/napi-postinstall/-/napi-postinstall-0.3.4.tgz#7af256d6588b5f8e952b9190965d6b019653bbb9" + integrity sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +next-i18next@15.4.2: + version "15.4.2" + resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-15.4.2.tgz#b2bc80ad77e92433e6bf2821bbb76c2630347495" + integrity sha512-zgRxWf7kdXtM686ecGIBQL+Bq0+DqAhRlasRZ3vVF0TmrNTWkVhs52n//oU3Fj5O7r/xOKkECDUwfOuXVwTK/g== + dependencies: + "@babel/runtime" "^7.23.2" + "@types/hoist-non-react-statics" "^3.3.6" + core-js "^3" + hoist-non-react-statics "^3.3.2" + i18next-fs-backend "^2.6.0" + +next@15.4.9: + version "15.4.9" + resolved "https://registry.yarnpkg.com/next/-/next-15.4.9.tgz#9204500a9c3cb2b981fb932077abfa66d3ef663f" + integrity sha512-/NedNmbiH4Umt/7SohT9VKxEdBt02Lj33xHrukE7d8Li6juT+75sEq4a4U06jggrvdbklKgr78OZEyWZ8XRrtw== + dependencies: + "@next/env" "15.4.9" + "@swc/helpers" "0.5.15" + caniuse-lite "^1.0.30001579" + postcss "8.4.31" + styled-jsx "5.1.6" + optionalDependencies: + "@next/swc-darwin-arm64" "15.4.8" + "@next/swc-darwin-x64" "15.4.8" + "@next/swc-linux-arm64-gnu" "15.4.8" + "@next/swc-linux-arm64-musl" "15.4.8" + "@next/swc-linux-x64-gnu" "15.4.8" + "@next/swc-linux-x64-musl" "15.4.8" + "@next/swc-win32-arm64-msvc" "15.4.8" + "@next/swc-win32-x64-msvc" "15.4.8" + sharp "^0.34.3" + +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4, object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +object.entries@^1.1.9: + version "1.1.9" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.9.tgz#e4770a6a1444afb61bd39f984018b5bede25f8b3" + integrity sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.4" + define-properties "^1.2.1" + es-object-atoms "^1.1.1" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.1.6, object.values@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + 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" + +own-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/own-keys/-/own-keys-1.0.1.tgz#e4006910a2bf913585289676eebd6f390cf51358" + integrity sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg== + dependencies: + get-intrinsic "^1.2.6" + object-keys "^1.1.1" + safe-push-apply "^1.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + 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" + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +pathe@^2.0.1, pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +picocolors@^1.0.0, picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +picomatch@^4.0.2, picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +pkg-types@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-1.3.1.tgz#bd7cc70881192777eef5326c19deb46e890917df" + integrity sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ== + dependencies: + confbox "^0.1.8" + mlly "^1.7.4" + pathe "^2.0.1" + +pkg-types@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pkg-types/-/pkg-types-2.3.0.tgz#037f2c19bd5402966ff6810e32706558cb5b5726" + integrity sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig== + dependencies: + confbox "^0.2.2" + exsolve "^1.0.7" + pathe "^2.0.3" + +playwright-core@1.56.1: + version "1.56.1" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.56.1.tgz#24a66481e5cd33a045632230aa2c4f0cb6b1db3d" + integrity sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ== + +playwright@1.56.1: + version "1.56.1" + resolved "https://registry.yarnpkg.com/playwright/-/playwright-1.56.1.tgz#62e3b99ddebed0d475e5936a152c88e68be55fbf" + integrity sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw== + dependencies: + playwright-core "1.56.1" + optionalDependencies: + fsevents "2.3.2" + +possible-typed-array-names@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz#93e3582bc0e5426586d9d07b79ee40fc841de4ae" + integrity sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg== + +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +postcss@^8.4.43, postcss@^8.5.3: + version "8.5.6" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.5.6.tgz#2825006615a619b4f62a9e7426cc120b349a8f3c" + integrity sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg== + dependencies: + nanoid "^3.3.11" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +posthog-js@1.293.0: + version "1.293.0" + resolved "https://registry.yarnpkg.com/posthog-js/-/posthog-js-1.293.0.tgz#ba662ea9953cdcdbd3f418880bb4bb68f5a04bf1" + integrity sha512-0KN3gVNbZPwEEWe5w6VH5Ql/+y113mwsl5TTEpOlAtN1ae6Ok18mQ6cS2K0X56GpF/dtdSoXQtnex6ZqUcdAcA== + dependencies: + "@posthog/core" "1.5.2" + core-js "^3.38.1" + fflate "^0.4.8" + preact "^10.19.3" + web-vitals "^4.2.4" + +preact@^10.19.3: + version "10.27.2" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.27.2.tgz#19b9009c1be801a76a0aaf0fe5ba665985a09312" + integrity sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.6.2.tgz#ccda02a1003ebbb2bfda6f83a074978f608b9393" + integrity sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ== + +pretty-bytes@7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-7.1.0.tgz#d788c9906241dbdcd4defab51b6d7470243db9bd" + integrity sha512-nODzvTiYVRGRqAOvE84Vk5JDPyyxsVk0/fbA/bq7RqlnhksGpset09XTxbpvLTIjoaF7K8Z8DG8yHtKGTPSYRw== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +quansync@^0.2.11: + version "0.2.11" + resolved "https://registry.yarnpkg.com/quansync/-/quansync-0.2.11.tgz#f9c3adda2e1272e4f8cf3f1457b04cbdb4ee692a" + integrity sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-arborist@3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/react-arborist/-/react-arborist-3.4.3.tgz#982791a07d1e279f279be88162c920112f3cee90" + integrity sha512-yFnq1nIQhT2uJY4TZVz2tgAiBb9lxSyvF4vC3S8POCK8xLzjGIxVv3/4dmYquQJ7AHxaZZArRGHiHKsEewKdTQ== + dependencies: + react-dnd "^14.0.3" + react-dnd-html5-backend "^14.0.3" + react-window "^1.8.11" + redux "^5.0.0" + use-sync-external-store "^1.2.0" + +react-aria-components@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/react-aria-components/-/react-aria-components-1.8.0.tgz#db8744ceae1d117d06f73b3de29b716a8b4ef7c3" + integrity sha512-qNJ/Z4opj1/NKFf1ch/V8rNYar5MXu4J8YVAt2pFgnBRLjVlIlfnENN8Oa5OFiYFCzMPRFdq5mI8RuYIEnvZfg== + dependencies: + "@internationalized/date" "^3.8.0" + "@internationalized/string" "^3.2.6" + "@react-aria/autocomplete" "3.0.0-beta.2" + "@react-aria/collections" "3.0.0-rc.0" + "@react-aria/dnd" "^3.9.2" + "@react-aria/focus" "^3.20.2" + "@react-aria/interactions" "^3.25.0" + "@react-aria/live-announcer" "^3.4.2" + "@react-aria/overlays" "^3.27.0" + "@react-aria/ssr" "^3.9.8" + "@react-aria/toolbar" "3.0.0-beta.15" + "@react-aria/utils" "^3.28.2" + "@react-aria/virtualizer" "^4.1.4" + "@react-stately/autocomplete" "3.0.0-beta.1" + "@react-stately/layout" "^4.2.2" + "@react-stately/selection" "^3.20.1" + "@react-stately/table" "^3.14.1" + "@react-stately/utils" "^3.10.6" + "@react-stately/virtualizer" "^4.3.2" + "@react-types/form" "^3.7.11" + "@react-types/grid" "^3.3.1" + "@react-types/shared" "^3.29.0" + "@react-types/table" "^3.12.0" + "@swc/helpers" "^0.5.0" + client-only "^0.0.1" + react-aria "^3.39.0" + react-stately "^3.37.0" + use-sync-external-store "^1.4.0" + +react-aria@3.39.0: + version "3.39.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.39.0.tgz#68e01a25365f403cfbc870b7ec29093d8722f0ba" + integrity sha512-zXCjR01WnfW4uW0f294uWrvdfwEMHgDFSwMwMBwRafAvmsQea87X5VTAfDmQOAbPa+iQFcngIyH0Pn5CfXNrjw== + dependencies: + "@internationalized/string" "^3.2.6" + "@react-aria/breadcrumbs" "^3.5.23" + "@react-aria/button" "^3.13.0" + "@react-aria/calendar" "^3.8.0" + "@react-aria/checkbox" "^3.15.4" + "@react-aria/color" "^3.0.6" + "@react-aria/combobox" "^3.12.2" + "@react-aria/datepicker" "^3.14.2" + "@react-aria/dialog" "^3.5.24" + "@react-aria/disclosure" "^3.0.4" + "@react-aria/dnd" "^3.9.2" + "@react-aria/focus" "^3.20.2" + "@react-aria/gridlist" "^3.12.0" + "@react-aria/i18n" "^3.12.8" + "@react-aria/interactions" "^3.25.0" + "@react-aria/label" "^3.7.17" + "@react-aria/landmark" "^3.0.2" + "@react-aria/link" "^3.8.0" + "@react-aria/listbox" "^3.14.3" + "@react-aria/menu" "^3.18.2" + "@react-aria/meter" "^3.4.22" + "@react-aria/numberfield" "^3.11.13" + "@react-aria/overlays" "^3.27.0" + "@react-aria/progress" "^3.4.22" + "@react-aria/radio" "^3.11.2" + "@react-aria/searchfield" "^3.8.3" + "@react-aria/select" "^3.15.4" + "@react-aria/selection" "^3.24.0" + "@react-aria/separator" "^3.4.8" + "@react-aria/slider" "^3.7.18" + "@react-aria/ssr" "^3.9.8" + "@react-aria/switch" "^3.7.2" + "@react-aria/table" "^3.17.2" + "@react-aria/tabs" "^3.10.2" + "@react-aria/tag" "^3.5.2" + "@react-aria/textfield" "^3.17.2" + "@react-aria/toast" "^3.0.2" + "@react-aria/tooltip" "^3.8.2" + "@react-aria/tree" "^3.0.2" + "@react-aria/utils" "^3.28.2" + "@react-aria/visually-hidden" "^3.8.22" + "@react-types/shared" "^3.29.0" + +react-aria@^3.39.0: + version "3.44.0" + resolved "https://registry.yarnpkg.com/react-aria/-/react-aria-3.44.0.tgz#6b694c704c0d438feb1baad23ab32cc7e8edb68f" + integrity sha512-2Pq3GQxBgM4/2BlpKYXeaZ47a3tdIcYSW/AYvKgypE3XipxOdQMDG5Sr/NBn7zuJq+thzmtfRb0lB9bTbsmaRw== + dependencies: + "@internationalized/string" "^3.2.7" + "@react-aria/breadcrumbs" "^3.5.29" + "@react-aria/button" "^3.14.2" + "@react-aria/calendar" "^3.9.2" + "@react-aria/checkbox" "^3.16.2" + "@react-aria/color" "^3.1.2" + "@react-aria/combobox" "^3.14.0" + "@react-aria/datepicker" "^3.15.2" + "@react-aria/dialog" "^3.5.31" + "@react-aria/disclosure" "^3.1.0" + "@react-aria/dnd" "^3.11.3" + "@react-aria/focus" "^3.21.2" + "@react-aria/gridlist" "^3.14.1" + "@react-aria/i18n" "^3.12.13" + "@react-aria/interactions" "^3.25.6" + "@react-aria/label" "^3.7.22" + "@react-aria/landmark" "^3.0.7" + "@react-aria/link" "^3.8.6" + "@react-aria/listbox" "^3.15.0" + "@react-aria/menu" "^3.19.3" + "@react-aria/meter" "^3.4.27" + "@react-aria/numberfield" "^3.12.2" + "@react-aria/overlays" "^3.30.0" + "@react-aria/progress" "^3.4.27" + "@react-aria/radio" "^3.12.2" + "@react-aria/searchfield" "^3.8.9" + "@react-aria/select" "^3.17.0" + "@react-aria/selection" "^3.26.0" + "@react-aria/separator" "^3.4.13" + "@react-aria/slider" "^3.8.2" + "@react-aria/ssr" "^3.9.10" + "@react-aria/switch" "^3.7.8" + "@react-aria/table" "^3.17.8" + "@react-aria/tabs" "^3.10.8" + "@react-aria/tag" "^3.7.2" + "@react-aria/textfield" "^3.18.2" + "@react-aria/toast" "^3.0.8" + "@react-aria/tooltip" "^3.8.8" + "@react-aria/tree" "^3.1.4" + "@react-aria/utils" "^3.31.0" + "@react-aria/visually-hidden" "^3.8.28" + "@react-types/shared" "^3.32.1" + +react-dnd-html5-backend@^14.0.3: + version "14.1.0" + resolved "https://registry.yarnpkg.com/react-dnd-html5-backend/-/react-dnd-html5-backend-14.1.0.tgz#b35a3a0c16dd3a2bfb5eb7ec62cf0c2cace8b62f" + integrity sha512-6ONeqEC3XKVf4eVmMTe0oPds+c5B9Foyj8p/ZKLb7kL2qh9COYxiBHv3szd6gztqi/efkmriywLUVlPotqoJyw== + dependencies: + dnd-core "14.0.1" + +react-dnd@^14.0.3: + version "14.0.5" + resolved "https://registry.yarnpkg.com/react-dnd/-/react-dnd-14.0.5.tgz#ecf264e220ae62e35634d9b941502f3fca0185ed" + integrity sha512-9i1jSgbyVw0ELlEVt/NkCUkxy1hmhJOkePoCH713u75vzHGyXhPDm28oLfc2NMSBjZRM1Y+wRjHXJT3sPrTy+A== + dependencies: + "@react-dnd/invariant" "^2.0.0" + "@react-dnd/shallowequal" "^2.0.0" + dnd-core "14.0.1" + fast-deep-equal "^3.1.3" + hoist-non-react-statics "^3.3.2" + +react-dom@19.2.0: + version "19.2.0" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-19.2.0.tgz#00ed1e959c365e9a9d48f8918377465466ec3af8" + integrity sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ== + dependencies: + scheduler "^0.27.0" + +react-dropzone@14.3.8: + version "14.3.8" + resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-14.3.8.tgz#a7eab118f8a452fe3f8b162d64454e81ba830582" + integrity sha512-sBgODnq+lcA4P296DY4wacOZz3JFpD99fp+hb//iBO2HHnyeZU3FwWyXJ6salNpqQdsZrgMrotuko/BdJMV8Ug== + dependencies: + attr-accept "^2.2.4" + file-selector "^2.1.0" + prop-types "^15.8.1" + +react-hook-form@7.66.0: + version "7.66.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.66.0.tgz#1a09ea9d0ebb3bdda5073b08a486538d37d9c0d4" + integrity sha512-xXBqsWGKrY46ZqaHDo+ZUYiMUgi8suYu5kdrS20EG8KiL7VRQitEbNjm+UcrDYrNi1YLyfpmAeGjCZYXLT9YBw== + +react-i18next@16.3.3: + version "16.3.3" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-16.3.3.tgz#098ff5443d0436a78692ca76303b2219aca32989" + integrity sha512-IaY2W+ueVd/fe7H6Wj2S4bTuLNChnajFUlZFfCTrTHWzGcOrUHlVzW55oXRSl+J51U8Onn6EvIhQ+Bar9FUcjw== + dependencies: + "@babel/runtime" "^7.27.6" + html-parse-stringify "^3.0.1" + use-sync-external-store "^1.6.0" + +react-is@18.2.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +react-lifecycles-compat@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" + integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== + +react-modal@3.16.3: + version "3.16.3" + resolved "https://registry.yarnpkg.com/react-modal/-/react-modal-3.16.3.tgz#c412d41915782e3c261253435d01468e2439b11b" + integrity sha512-yCYRJB5YkeQDQlTt17WGAgFJ7jr2QYcWa1SHqZ3PluDmnKJ/7+tVU+E6uKyZ0nODaeEj+xCpK4LcSnKXLMC0Nw== + dependencies: + exenv "^1.2.0" + prop-types "^15.7.2" + react-lifecycles-compat "^3.0.0" + warning "^4.0.3" + +react-refresh@^0.18.0: + version "0.18.0" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.18.0.tgz#2dce97f4fe932a4d8142fa1630e475c1729c8062" + integrity sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw== + +react-remove-scroll-bar@^2.3.7: + version "2.3.8" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz#99c20f908ee467b385b68a3469b4a3e750012223" + integrity sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q== + dependencies: + react-style-singleton "^2.2.2" + tslib "^2.0.0" + +react-remove-scroll@^2.6.3: + version "2.7.1" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz#d2101d414f6d81d7d3bf033f3c1cb4785789f753" + integrity sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA== + dependencies: + react-remove-scroll-bar "^2.3.7" + react-style-singleton "^2.2.3" + tslib "^2.1.0" + use-callback-ref "^1.3.3" + use-sidecar "^1.1.3" + +react-resizable-panels@2.1.7: + version "2.1.7" + resolved "https://registry.yarnpkg.com/react-resizable-panels/-/react-resizable-panels-2.1.7.tgz#afd29d8a3d708786a9f95183a38803c89f13c2e7" + integrity sha512-JtT6gI+nURzhMYQYsx8DKkx6bSoOGFp7A3CwMrOb8y5jFHFyqwo9m68UhmXRw57fRVJksFn1TSlm3ywEQ9vMgA== + +react-stately@3.37.0: + version "3.37.0" + resolved "https://registry.yarnpkg.com/react-stately/-/react-stately-3.37.0.tgz#9bd09ecd1c7b11461ec60e17a7c670c17a64962e" + integrity sha512-fm2LRM3XN5lJD48+WQKWvESx54kAIHw0JztCRHMsFmTDgYWX/VASuXKON7LECv227stSEadrxGa8LhPkcelljw== + dependencies: + "@react-stately/calendar" "^3.8.0" + "@react-stately/checkbox" "^3.6.13" + "@react-stately/collections" "^3.12.3" + "@react-stately/color" "^3.8.4" + "@react-stately/combobox" "^3.10.4" + "@react-stately/data" "^3.12.3" + "@react-stately/datepicker" "^3.14.0" + "@react-stately/disclosure" "^3.0.3" + "@react-stately/dnd" "^3.5.3" + "@react-stately/form" "^3.1.3" + "@react-stately/list" "^3.12.1" + "@react-stately/menu" "^3.9.3" + "@react-stately/numberfield" "^3.9.11" + "@react-stately/overlays" "^3.6.15" + "@react-stately/radio" "^3.10.12" + "@react-stately/searchfield" "^3.5.11" + "@react-stately/select" "^3.6.12" + "@react-stately/selection" "^3.20.1" + "@react-stately/slider" "^3.6.3" + "@react-stately/table" "^3.14.1" + "@react-stately/tabs" "^3.8.1" + "@react-stately/toast" "^3.1.0" + "@react-stately/toggle" "^3.8.3" + "@react-stately/tooltip" "^3.5.3" + "@react-stately/tree" "^3.8.9" + "@react-types/shared" "^3.29.0" + +react-stately@^3.37.0: + version "3.42.0" + resolved "https://registry.yarnpkg.com/react-stately/-/react-stately-3.42.0.tgz#f309e9cb729374cc187c688529a2aa0572ab9408" + integrity sha512-lYt2o1dd6dK8Bb4GRh08RG/2u64bSA1cqtRqtw4jEMgxC7Q17RFcIumBbChErndSdLzafEG/UBwV6shOfig6yw== + dependencies: + "@react-stately/calendar" "^3.9.0" + "@react-stately/checkbox" "^3.7.2" + "@react-stately/collections" "^3.12.8" + "@react-stately/color" "^3.9.2" + "@react-stately/combobox" "^3.12.0" + "@react-stately/data" "^3.14.1" + "@react-stately/datepicker" "^3.15.2" + "@react-stately/disclosure" "^3.0.8" + "@react-stately/dnd" "^3.7.1" + "@react-stately/form" "^3.2.2" + "@react-stately/list" "^3.13.1" + "@react-stately/menu" "^3.9.8" + "@react-stately/numberfield" "^3.10.2" + "@react-stately/overlays" "^3.6.20" + "@react-stately/radio" "^3.11.2" + "@react-stately/searchfield" "^3.5.16" + "@react-stately/select" "^3.8.0" + "@react-stately/selection" "^3.20.6" + "@react-stately/slider" "^3.7.2" + "@react-stately/table" "^3.15.1" + "@react-stately/tabs" "^3.8.6" + "@react-stately/toast" "^3.1.2" + "@react-stately/toggle" "^3.9.2" + "@react-stately/tooltip" "^3.5.8" + "@react-stately/tree" "^3.9.3" + "@react-types/shared" "^3.32.1" + +react-style-singleton@^2.2.2, react-style-singleton@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.2.3.tgz#4265608be69a4d70cfe3047f2c6c88b2c3ace388" + integrity sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ== + dependencies: + get-nonce "^1.0.0" + tslib "^2.0.0" + +react-toastify@11.0.5: + version "11.0.5" + resolved "https://registry.yarnpkg.com/react-toastify/-/react-toastify-11.0.5.tgz#ce4c42d10eeb433988ab2264d3e445c4e9d13313" + integrity sha512-EpqHBGvnSTtHYhCPLxML05NLY2ZX0JURbAdNYa6BUkk+amz4wbKBQvoKQAB0ardvSarUBuY4Q4s1sluAzZwkmA== + dependencies: + clsx "^2.1.1" + +react-window@^1.8.11: + version "1.8.11" + resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.11.tgz#a857b48fa85bd77042d59cc460964ff2e0648525" + integrity sha512-+SRbUVT2scadgFSWx+R1P754xHPEqvcfSfVX10QYg6POOz+WNgkN48pS+BtZNIMGiL1HYrSEiCkwsMS15QogEQ== + dependencies: + "@babel/runtime" "^7.0.0" + memoize-one ">=3.1.1 <6" + +react@19.2.0: + version "19.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-19.2.0.tgz#d33dd1721698f4376ae57a54098cb47fc75d93a5" + integrity sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ== + +readdirp@^4.0.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-4.1.2.tgz#eb85801435fbf2a7ee58f19e0921b068fc69948d" + integrity sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg== + +redux@^4.1.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197" + integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== + dependencies: + "@babel/runtime" "^7.9.2" + +redux@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/redux/-/redux-5.0.1.tgz#97fa26881ce5746500125585d5642c77b6e9447b" + integrity sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w== + +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz#c629219e78a3316d8b604c765ef68996964e7bf9" + integrity sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.9" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.7" + get-proto "^1.0.1" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3, regexp.prototype.flags@^1.5.4: + version "1.5.4" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz#1ad6c62d44a259007e55b3970e00f746efbcaa19" + integrity sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-errors "^1.3.0" + get-proto "^1.0.1" + gopd "^1.2.0" + set-function-name "^2.0.2" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve.exports@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== + +resolve@^1.20.0, resolve@^1.22.4, resolve@~1.22.1, resolve@~1.22.2: + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== + dependencies: + is-core-module "^2.16.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +resolve@^2.0.0-next.5: + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +rollup@^4.20.0, rollup@^4.34.9: + version "4.53.3" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.53.3.tgz#dbc8cd8743b38710019fb8297e8d7a76e3faa406" + integrity sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA== + dependencies: + "@types/estree" "1.0.8" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.53.3" + "@rollup/rollup-android-arm64" "4.53.3" + "@rollup/rollup-darwin-arm64" "4.53.3" + "@rollup/rollup-darwin-x64" "4.53.3" + "@rollup/rollup-freebsd-arm64" "4.53.3" + "@rollup/rollup-freebsd-x64" "4.53.3" + "@rollup/rollup-linux-arm-gnueabihf" "4.53.3" + "@rollup/rollup-linux-arm-musleabihf" "4.53.3" + "@rollup/rollup-linux-arm64-gnu" "4.53.3" + "@rollup/rollup-linux-arm64-musl" "4.53.3" + "@rollup/rollup-linux-loong64-gnu" "4.53.3" + "@rollup/rollup-linux-ppc64-gnu" "4.53.3" + "@rollup/rollup-linux-riscv64-gnu" "4.53.3" + "@rollup/rollup-linux-riscv64-musl" "4.53.3" + "@rollup/rollup-linux-s390x-gnu" "4.53.3" + "@rollup/rollup-linux-x64-gnu" "4.53.3" + "@rollup/rollup-linux-x64-musl" "4.53.3" + "@rollup/rollup-openharmony-arm64" "4.53.3" + "@rollup/rollup-win32-arm64-msvc" "4.53.3" + "@rollup/rollup-win32-ia32-msvc" "4.53.3" + "@rollup/rollup-win32-x64-gnu" "4.53.3" + "@rollup/rollup-win32-x64-msvc" "4.53.3" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + +safe-push-apply@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/safe-push-apply/-/safe-push-apply-1.0.0.tgz#01850e981c1602d398c85081f360e4e6d03d27f5" + integrity sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA== + dependencies: + es-errors "^1.3.0" + isarray "^2.0.5" + +safe-regex-test@^1.0.3, safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + +sass@1.94.0: + version "1.94.0" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.94.0.tgz#a04198d8940358ca6ad537d2074051edbbe7c1a7" + integrity sha512-Dqh7SiYcaFtdv5Wvku6QgS5IGPm281L+ZtVD1U2FJa7Q0EFRlq8Z3sjYtz6gYObsYThUOz9ArwFqPZx+1azILQ== + dependencies: + chokidar "^4.0.0" + immutable "^5.0.2" + source-map-js ">=0.6.2 <2.0.0" + optionalDependencies: + "@parcel/watcher" "^2.4.1" + +scheduler@^0.27.0: + version "0.27.0" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.27.0.tgz#0c4ef82d67d1e5c1e359e8fc76d3a87f045fe5bd" + integrity sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3, semver@^7.7.1, semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== + +semver@~7.5.4: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +set-function-length@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + +set-proto@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/set-proto/-/set-proto-1.0.0.tgz#0760dbcff30b2d7e801fd6e19983e56da337565e" + integrity sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw== + dependencies: + dunder-proto "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + +sharp@^0.34.3: + version "0.34.5" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.5.tgz#b6f148e4b8c61f1797bde11a9d1cfebbae2c57b0" + integrity sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg== + dependencies: + "@img/colour" "^1.0.0" + detect-libc "^2.1.2" + semver "^7.7.3" + optionalDependencies: + "@img/sharp-darwin-arm64" "0.34.5" + "@img/sharp-darwin-x64" "0.34.5" + "@img/sharp-libvips-darwin-arm64" "1.2.4" + "@img/sharp-libvips-darwin-x64" "1.2.4" + "@img/sharp-libvips-linux-arm" "1.2.4" + "@img/sharp-libvips-linux-arm64" "1.2.4" + "@img/sharp-libvips-linux-ppc64" "1.2.4" + "@img/sharp-libvips-linux-riscv64" "1.2.4" + "@img/sharp-libvips-linux-s390x" "1.2.4" + "@img/sharp-libvips-linux-x64" "1.2.4" + "@img/sharp-libvips-linuxmusl-arm64" "1.2.4" + "@img/sharp-libvips-linuxmusl-x64" "1.2.4" + "@img/sharp-linux-arm" "0.34.5" + "@img/sharp-linux-arm64" "0.34.5" + "@img/sharp-linux-ppc64" "0.34.5" + "@img/sharp-linux-riscv64" "0.34.5" + "@img/sharp-linux-s390x" "0.34.5" + "@img/sharp-linux-x64" "0.34.5" + "@img/sharp-linuxmusl-arm64" "0.34.5" + "@img/sharp-linuxmusl-x64" "0.34.5" + "@img/sharp-wasm32" "0.34.5" + "@img/sharp-win32-arm64" "0.34.5" + "@img/sharp-win32-ia32" "0.34.5" + "@img/sharp-win32-x64" "0.34.5" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + 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" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + 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" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +"source-map-js@>=0.6.2 <2.0.0", source-map-js@^1.0.2, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stable-hash@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.5.tgz#94e8837aaeac5b4d0f631d2972adef2924b40269" + integrity sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +stop-iteration-iterator@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz#f481ff70a548f6124d0312c3aa14cbfa7aa542ad" + integrity sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ== + dependencies: + es-errors "^1.3.0" + internal-slot "^1.1.0" + +string-argv@~0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.2.tgz#2b6d0ef24b656274d957d54e0a4bbf6153dc02b6" + integrity sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string.prototype.includes@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz#eceef21283640761a81dbe16d6c7171a4edf7d92" + integrity sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.3" + +string.prototype.matchall@^4.0.12: + version "4.0.12" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz#6c88740e49ad4956b1332a911e949583a275d4c0" + integrity sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + has-symbols "^1.1.0" + internal-slot "^1.1.0" + regexp.prototype.flags "^1.5.3" + set-function-name "^2.0.2" + side-channel "^1.1.0" + +string.prototype.repeat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz#e90872ee0308b29435aa26275f6e1b762daee01a" + integrity sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.17.5" + +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1, strip-json-comments@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +styled-jsx@5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499" + integrity sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA== + dependencies: + client-only "0.0.1" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0, supports-color@~8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +tinyglobby@^0.2.13: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== + +ts-jest@29.2.5: + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== + dependencies: + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.6.3" + yargs-parser "^21.1.1" + +ts-node@10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.0.0, tslib@^2.1.0, tslib@^2.4.0, tslib@^2.6.2, tslib@^2.7.0, tslib@^2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +turbo-darwin-64@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-2.6.1.tgz#62be8b3033c166103c6e6368bc37a29ebd9f5a1e" + integrity sha512-Dm0HwhyZF4J0uLqkhUyCVJvKM9Rw7M03v3J9A7drHDQW0qAbIGBrUijQ8g4Q9Cciw/BXRRd8Uzkc3oue+qn+ZQ== + +turbo-darwin-arm64@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-2.6.1.tgz#41482448cd40f226237d97ca1892572f93d488e5" + integrity sha512-U0PIPTPyxdLsrC3jN7jaJUwgzX5sVUBsKLO7+6AL+OASaa1NbT1pPdiZoTkblBAALLP76FM0LlnsVQOnmjYhyw== + +turbo-linux-64@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-2.6.1.tgz#1b47a28a3387858eb9c17ff77660180265074659" + integrity sha512-eM1uLWgzv89bxlK29qwQEr9xYWBhmO/EGiH22UGfq+uXr+QW1OvNKKMogSN65Ry8lElMH4LZh0aX2DEc7eC0Mw== + +turbo-linux-arm64@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-2.6.1.tgz#7cc9b42c70cc37f8799312c586a914bd8b78c944" + integrity sha512-MFFh7AxAQAycXKuZDrbeutfWM5Ep0CEZ9u7zs4Hn2FvOViTCzIfEhmuJou3/a5+q5VX1zTxQrKGy+4Lf5cdpsA== + +turbo-windows-64@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-2.6.1.tgz#c367296dd5f1465f1a1071ac987ba179b956531a" + integrity sha512-buq7/VAN7KOjMYi4tSZT5m+jpqyhbRU2EUTTvp6V0Ii8dAkY2tAAjQN1q5q2ByflYWKecbQNTqxmVploE0LVwQ== + +turbo-windows-arm64@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo-windows-arm64/-/turbo-windows-arm64-2.6.1.tgz#530eafbcf46a2b7ed2f183a6a32a25a9c8901287" + integrity sha512-7w+AD5vJp3R+FB0YOj1YJcNcOOvBior7bcHTodqp90S3x3bLgpr7tE6xOea1e8JkP7GK6ciKVUpQvV7psiwU5Q== + +turbo@2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/turbo/-/turbo-2.6.1.tgz#12107e157f49e6bb3fbcf54025d55fd7f30b9c7c" + integrity sha512-qBwXXuDT3rA53kbNafGbT5r++BrhRgx3sAo0cHoDAeG9g1ItTmUMgltz3Hy7Hazy1ODqNpR+C7QwqL6DYB52yA== + optionalDependencies: + turbo-darwin-64 "2.6.1" + turbo-darwin-arm64 "2.6.1" + turbo-linux-64 "2.6.1" + turbo-linux-arm64 "2.6.1" + turbo-windows-64 "2.6.1" + turbo-windows-arm64 "2.6.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + +typescript-eslint@^8.30.1: + version "8.47.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.47.0.tgz#bb8fcf4f2c69ffcd5d088f7f30cd52936ff05cbc" + integrity sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q== + dependencies: + "@typescript-eslint/eslint-plugin" "8.47.0" + "@typescript-eslint/parser" "8.47.0" + "@typescript-eslint/typescript-estree" "8.47.0" + "@typescript-eslint/utils" "8.47.0" + +typescript@5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + +typescript@5.8.2: + version "5.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" + integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== + +typescript@5.9.3, typescript@~5.9.0: + version "5.9.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" + integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== + +ufo@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/ufo/-/ufo-1.6.1.tgz#ac2db1d54614d1b22c1d603e3aef44a85d8f146b" + integrity sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA== + +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== + +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +unrs-resolver@^1.6.2: + version "1.11.1" + resolved "https://registry.yarnpkg.com/unrs-resolver/-/unrs-resolver-1.11.1.tgz#be9cd8686c99ef53ecb96df2a473c64d304048a9" + integrity sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg== + dependencies: + napi-postinstall "^0.3.0" + optionalDependencies: + "@unrs/resolver-binding-android-arm-eabi" "1.11.1" + "@unrs/resolver-binding-android-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-arm64" "1.11.1" + "@unrs/resolver-binding-darwin-x64" "1.11.1" + "@unrs/resolver-binding-freebsd-x64" "1.11.1" + "@unrs/resolver-binding-linux-arm-gnueabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm-musleabihf" "1.11.1" + "@unrs/resolver-binding-linux-arm64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-arm64-musl" "1.11.1" + "@unrs/resolver-binding-linux-ppc64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-riscv64-musl" "1.11.1" + "@unrs/resolver-binding-linux-s390x-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-gnu" "1.11.1" + "@unrs/resolver-binding-linux-x64-musl" "1.11.1" + "@unrs/resolver-binding-wasm32-wasi" "1.11.1" + "@unrs/resolver-binding-win32-arm64-msvc" "1.11.1" + "@unrs/resolver-binding-win32-ia32-msvc" "1.11.1" + "@unrs/resolver-binding-win32-x64-msvc" "1.11.1" + +update-browserslist-db@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.4.tgz#7802aa2ae91477f255b86e0e46dbc787a206ad4a" + integrity sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2, uri-js@^4.4.1: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +use-callback-ref@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.3.3.tgz#98d9fab067075841c5b2c6852090d5d0feabe2bf" + integrity sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg== + dependencies: + tslib "^2.0.0" + +use-sidecar@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.1.3.tgz#10e7fd897d130b896e2c546c63a5e8233d00efdb" + integrity sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ== + dependencies: + detect-node-es "^1.1.0" + tslib "^2.0.0" + +use-sync-external-store@^1.2.0, use-sync-external-store@^1.2.2, use-sync-external-store@^1.4.0, use-sync-external-store@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz#b174bfa65cb2b526732d9f2ac0a408027876f32d" + integrity sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vite-plugin-dts@4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz#51b60aaaa760d9cf5c2bb3676c69d81910d6b08c" + integrity sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg== + dependencies: + "@microsoft/api-extractor" "^7.50.1" + "@rollup/pluginutils" "^5.1.4" + "@volar/typescript" "^2.4.11" + "@vue/language-core" "2.2.0" + compare-versions "^6.1.1" + debug "^4.4.0" + kolorist "^1.8.0" + local-pkg "^1.0.0" + magic-string "^0.30.17" + +vite@5.4.21: + version "5.4.21" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.21.tgz#84a4f7c5d860b071676d39ba513c0d598fdc7027" + integrity sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw== + dependencies: + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" + optionalDependencies: + fsevents "~2.3.3" + +vite@^6.3.5: + version "6.4.1" + resolved "https://registry.yarnpkg.com/vite/-/vite-6.4.1.tgz#afbe14518cdd6887e240a4b0221ab6d0ce733f96" + integrity sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g== + dependencies: + esbuild "^0.25.0" + fdir "^6.4.4" + picomatch "^4.0.2" + postcss "^8.5.3" + rollup "^4.34.9" + tinyglobby "^0.2.13" + optionalDependencies: + fsevents "~2.3.3" + +void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== + +vscode-uri@^3.0.8: + version "3.1.0" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-3.1.0.tgz#dd09ec5a66a38b5c3fffc774015713496d14e09c" + integrity sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + +web-vitals@^4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/web-vitals/-/web-vitals-4.2.4.tgz#1d20bc8590a37769bd0902b289550936069184b7" + integrity sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw== + +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.16, which-typed-array@^1.1.19: + version "1.1.19" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.19.tgz#df03842e870b6b88e117524a4b364b6fc689f956" + integrity sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.4" + for-each "^0.3.5" + get-proto "^1.0.1" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +"zod-validation-error@^3.5.0 || ^4.0.0": + version "4.0.2" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918" + integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== + +"zod@^3.25.0 || ^4.0.0": + version "4.1.12" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.1.12.tgz#64f1ea53d00eab91853195653b5af9eee68970f0" + integrity sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ== diff --git a/src/nginx/servers.conf.erb b/src/nginx/servers.conf.erb new file mode 100644 index 0000000..c003d9d --- /dev/null +++ b/src/nginx/servers.conf.erb @@ -0,0 +1,54 @@ +# ERB templated nginx configuration +# see https://doc.scalingo.com/platform/deployment/buildpacks/nginx + +upstream backend_server { + server localhost:8000 fail_timeout=0; +} + +server { + + listen <%= ENV["PORT"] %>; + server_name _; + + root /app/build/frontend-out; + + error_page 404 /404.html; + + # Django rest framework and external API + location ~ ^/(api|external_api)/ { + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_redirect off; + proxy_pass http://backend_server; + } + + # Django admin + location ^~ /admin/ { + proxy_set_header X-Forwarded-Proto https; + proxy_set_header Host $http_host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + proxy_redirect off; + proxy_pass http://backend_server; + } + + location ~ "^/401/?$" { + try_files $uri /401.html; + } + + location ~ "^/403/?$" { + try_files $uri /403.html; + } + + location = /404.html { + internal; + } + + # Frontend export + location / { + try_files $uri index.html $uri/ =404; + } + +}